/* Copyright 2011 Jacob Palnick
   
   This library is free software; you can redistribute it and/or modify
   it under the terms of version 3 of the GNU Lesser General Public 
   License as published by the Free Software Foundation.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
   GNU Lesser General Public License for more details.
   
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the 
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
   Boston, MA 02111-1307  USA
   
   You can contact Jacob Palnick by sending e-mail to
   jpalnick@me.com. Please include "java-dnd-character" in the
   subject line.
 */

package dndapplication.data.character;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;
import java.util.List;

import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.Serializer;

/**
 * an implementation of the dnd v3.5 character using java
 * 
 * @author Jacob Palnick
 */
public class Character {

	//FIXME having trouble reading the speed and hp values
	//TODO consider making the attack bonus a string to allow for  variable modifiers
	
	//FIXME add javadoc info for each method and class
	
	// enum

	/**
	 * an Enum that is used to specify which saving throw to reffer to.
	 */
	public enum SavingThrow {
		FORTITUDE, REFLEX, WILL
	};

	/**
	 * an Enum that is used to specify which saving throw to reffer to.
	 */
	public enum Ability {
		STRENGTH, DEXTERITY, CONSTITUTION, INTELLIGENCE, WISDOM, CHARISMA
	}

	// subclasses

	/**
	 * information about domains/specialty school/arcane spell failure
	 * 
	 * @author Jacob Palnick
	 */
	public static class Magic {

		// TODO learn how domains work and implement basic functions
		public String domain1;
		public String grantedPowers1;
		public String domain2;
		public String grantedPowers2;

		// TODO learn about specialty schools and implement basic functions
		public String specialtySchool;
		public String prohibitedSchool1;
		public String prohibitedSchool2;

		public int arcaneSpellFailure;

		/**
		 * creates a blank instance of Magic
		 */
		public Magic() {
			domain1 = " ";
			grantedPowers1 = " ";
			domain2 = " ";
			grantedPowers2 = " ";

			specialtySchool = " ";
			prohibitedSchool1 = " ";
			prohibitedSchool2 = " ";

			arcaneSpellFailure = 0;
		}

		/**
		 * creates an instance of Magic and sets the variables based on the
		 * contents of the xml element
		 * 
		 * @param magicElement
		 *            a nu.xom element with the xml contents to define the
		 *            values of the internal variables
		 */
		public Magic(Element magicElement) {
			domain1 = magicElement.getChildElements("domain1").get(0).getValue();
			grantedPowers1 = magicElement.getChildElements("grantedPowers1").get(0).getValue();
			domain2 = magicElement.getChildElements("domain2").get(0).getValue();
			grantedPowers2 = magicElement.getChildElements("grantedPowers2").get(0).getValue();

			specialtySchool = magicElement.getChildElements("specialtySchool").get(0).getValue();
			prohibitedSchool1 = magicElement.getChildElements("prohibitedSchool1").get(0).getValue();
			prohibitedSchool2 = magicElement.getChildElements("prohibitedSchool2").get(0).getValue();

			arcaneSpellFailure = Integer.parseInt(magicElement.getChildElements("arcaneSpellFailure").get(0).getValue());
		}

		/**
		 * the state of the Magic instance saved in a xml element
		 * 
		 * @return xml element containing the values of the internal variables
		 */
		public Element getMagicElement() {
			Element magicElement = new Element("magic");

			Element domain1Element = new Element("domain1");
			domain1Element.appendChild(domain1);
			magicElement.appendChild(domain1Element);

			Element grantedPowers1Element = new Element("grantedPowers1");
			grantedPowers1Element.appendChild(grantedPowers1);
			magicElement.appendChild(grantedPowers1Element);

			Element domain2Element = new Element("domain2");
			domain2Element.appendChild(domain2);
			magicElement.appendChild(domain2Element);

			Element grantedPowers2Element = new Element("grantedPowers2");
			grantedPowers2Element.appendChild(grantedPowers2);
			magicElement.appendChild(grantedPowers2Element);

			Element specialtySchoolElement = new Element("specialtySchool");
			specialtySchoolElement.appendChild(specialtySchool);
			magicElement.appendChild(specialtySchoolElement);

			Element prohibitedSchool1Element = new Element("prohibitedSchool1");
			prohibitedSchool1Element.appendChild(prohibitedSchool1);
			magicElement.appendChild(prohibitedSchool1Element);

			Element prohibitedSchool2Element = new Element("prohibitedSchool2");
			prohibitedSchool2Element.appendChild(prohibitedSchool2);
			magicElement.appendChild(prohibitedSchool2Element);

			Element arcaneSpellFailureElement = new Element("arcaneSpellFailure");
			arcaneSpellFailureElement.appendChild("" + arcaneSpellFailure);
			magicElement.appendChild(arcaneSpellFailureElement);

			return magicElement;

		}
	}

	/**
	 * contains all the information for magic items worn by the character
	 * 
	 * @author Jacob Palnick
	 * 
	 */
	public static class MagicItems {

		/**
		 * contains information and method relating to individual magic items
		 * 
		 * @author jpalnick
		 * 
		 */
		public class MagicItem {

			/**
			 * the name of the item
			 */
			public String itemName;
			/**
			 * a description of the magic item
			 */
			public String descrption;

			// TODO add variables to contain information about how the item
			// affects the character

			// FIXME add method to create a new magic item using strings

			/**
			 * creates a blank magic item. this is mainly used fo rcreating a
			 * new character and testing
			 */
			public MagicItem() {

				itemName = " ";
				descrption = " ";
			}

			/**
			 * creates a magic item based on the provided xml element
			 * 
			 * @param magicItemElement
			 *            nu.xom.Element containing the information to create an
			 *            "filled" magic item
			 */
			public MagicItem(Element magicItemElement) {
				itemName = magicItemElement.getChildElements("itemName").get(0).getValue();
				descrption = magicItemElement.getChildElements("description").get(0).getValue();
			}

			/**
			 * creates a xml element that contains the values of the internal
			 * variables. this is used to save the character data to a file
			 * 
			 * @param name
			 *            the name of the element. in this case it is the name
			 *            of the location it is being worn on
			 * @return nu.xom.Element
			 */
			public Element getMagicItemElement(String name) {
				Element magicItemElement = new Element(name);

				// TODO simplify the export code?
				Element itemNameElement = new Element("itemName");
				itemNameElement.appendChild(itemName);
				magicItemElement.appendChild(itemNameElement);

				Element descriptionElement = new Element("description");
				descriptionElement.appendChild(descrption);
				magicItemElement.appendChild(descriptionElement);

				return magicItemElement;
			}
		}

		/**
		 * magic item worn on the head
		 */
		public MagicItem head;
		/**
		 * magic item worn on hands
		 */
		public MagicItem hands;
		public MagicItem eyes;
		public MagicItem arms;
		public MagicItem neck;
		public MagicItem body;
		public MagicItem shoulders;
		public MagicItem torso;
		public MagicItem ring1;
		public MagicItem ring2;
		public MagicItem waist;
		public MagicItem feet;

		/**
		 * creates blank MagicItems for each position.
		 */
		public MagicItems() {
			head = new MagicItem();
			hands = new MagicItem();
			eyes = new MagicItem();
			arms = new MagicItem();
			neck = new MagicItem();
			body = new MagicItem();
			shoulders = new MagicItem();
			torso = new MagicItem();
			ring1 = new MagicItem();
			ring2 = new MagicItem();
			waist = new MagicItem();
			feet = new MagicItem();
		}

		/**
		 * creates Magic items at each location based on the xml in the provided
		 * Element
		 * 
		 * @param magicItemsElement
		 *            nu.xom.Element containting the data for the magic items
		 */
		public MagicItems(Element magicItemsElement) {
			head = new MagicItem(magicItemsElement.getChildElements("head").get(0));
			hands = new MagicItem(magicItemsElement.getChildElements("hands").get(0));
			eyes = new MagicItem(magicItemsElement.getChildElements("eyes").get(0));
			arms = new MagicItem(magicItemsElement.getChildElements("arms").get(0));
			neck = new MagicItem(magicItemsElement.getChildElements("neck").get(0));
			body = new MagicItem(magicItemsElement.getChildElements("body").get(0));
			shoulders = new MagicItem(magicItemsElement.getChildElements("shoulders").get(0));
			torso = new MagicItem(magicItemsElement.getChildElements("torso").get(0));
			ring1 = new MagicItem(magicItemsElement.getChildElements("ring1").get(0));
			ring2 = new MagicItem(magicItemsElement.getChildElements("ring2").get(0));
			waist = new MagicItem(magicItemsElement.getChildElements("waist").get(0));
			feet = new MagicItem(magicItemsElement.getChildElements("feet").get(0));

		}

		/**
		 * generate xml for the magic items
		 * 
		 * @return nu.xom.Element containing xml data of the magic items worn
		 */
		public Element getMagicItemsElement() {
			Element magicItemsElement = new Element("magicItems");

			magicItemsElement.appendChild(head.getMagicItemElement("head"));
			magicItemsElement.appendChild(hands.getMagicItemElement("hands"));
			magicItemsElement.appendChild(eyes.getMagicItemElement("eyes"));
			magicItemsElement.appendChild(arms.getMagicItemElement("arms"));
			magicItemsElement.appendChild(neck.getMagicItemElement("neck"));
			magicItemsElement.appendChild(body.getMagicItemElement("body"));
			magicItemsElement.appendChild(shoulders.getMagicItemElement("shoulders"));
			magicItemsElement.appendChild(torso.getMagicItemElement("torso"));
			magicItemsElement.appendChild(ring1.getMagicItemElement("ring1"));
			magicItemsElement.appendChild(ring2.getMagicItemElement("ring2"));
			magicItemsElement.appendChild(waist.getMagicItemElement("waist"));
			magicItemsElement.appendChild(feet.getMagicItemElement("feet"));

			return magicItemsElement;
		}
	}

	/**
	 * simple class to manage the money of the character
	 */
	public static class Money {

		public int CP;
		public int SP;
		public int GP;
		public int PP;

		/**
		 * creates new instance with all money set to 0
		 */
		public Money() {
			CP = 0;
			SP = 0;
			GP = 0;
			PP = 0;
		}

		/**
		 * creates new instace on Money with values set based on xml data
		 * provided
		 * 
		 * @param moneyElement
		 *            xml representation of the amounts of money
		 */
		public Money(Element moneyElement) {
			CP = Integer.parseInt(moneyElement.getChildElements("CP").get(0).getValue());
			SP = Integer.parseInt(moneyElement.getChildElements("SP").get(0).getValue());
			GP = Integer.parseInt(moneyElement.getChildElements("GP").get(0).getValue());
			PP = Integer.parseInt(moneyElement.getChildElements("PP").get(0).getValue());

		}

		/**
		 * create xml version of money
		 * 
		 * @return nu.xom.Element xml element containing voney values
		 */
		public Element getMoneyElement() {
			Element moneyElement = new Element("money");

			Element CPElement = new Element("CP");
			CPElement.appendChild("" + CP);
			moneyElement.appendChild(CPElement);

			Element SPElement = new Element("SP");
			SPElement.appendChild("" + SP);
			moneyElement.appendChild(SPElement);

			Element GPElement = new Element("GP");
			GPElement.appendChild("" + GP);
			moneyElement.appendChild(GPElement);

			Element PPElement = new Element("PP");
			PPElement.appendChild("" + PP);
			moneyElement.appendChild(PPElement);

			return moneyElement;
		}
	}

	/**
	 * a class to represent a basic item that would be carried by a character
	 * 
	 * @author Jacob Palnick
	 * 
	 */
	public static class Possession {

		public String itemName;
		public String location;
		public String weight;
		public int quantity;

		// TODO add variable to contain more information about the item. ex
		// description, use

		/**
		 * creates a blank item
		 */
		public Possession() {
			itemName = " ";
			location = " ";
			weight = " ";
			quantity = 0;
		}

		/**
		 * creates a new item
		 * 
		 * @param name
		 *            name of the item
		 * @param location
		 *            the location of the item
		 * @param weight
		 *            the weight of one of the item
		 * @param count
		 *            how many items does the character have
		 */
		public Possession(String name, String location, String weight, int count) {
			itemName = name;
			this.location = location;
			this.weight = weight;
			quantity = count;
		}

		/**
		 * creates a new item
		 * 
		 * @param possesionElement
		 *            xml data containing the name, location, weight, and
		 *            quantity
		 */
		public Possession(Element possesionElement) {
			itemName = possesionElement.getChildElements("itemName").get(0).getValue();
			location = possesionElement.getChildElements("location").get(0).getValue();
			weight = possesionElement.getChildElements("weight").get(0).getValue();
			quantity = Integer.parseInt(possesionElement.getChildElements("quantity").get(0).getValue());
		}

		/**
		 * generates a xml element with the data if this item/group of items
		 * 
		 * @return nu.xom.Element
		 */
		public Element getPossesionElement() {
			Element possessionElement = new Element("possesion");

			Element itemNameElement = new Element("itemName");
			itemNameElement.appendChild(itemName);
			possessionElement.appendChild(itemNameElement);

			Element locationElement = new Element("location");
			locationElement.appendChild(location);
			possessionElement.appendChild(locationElement);

			Element weightElement = new Element("weight");
			weightElement.appendChild(weight);
			possessionElement.appendChild(weightElement);

			Element quantityElement = new Element("quantity");
			quantityElement.appendChild("" + quantity);
			possessionElement.appendChild(quantityElement);

			return possessionElement;
		}
	}

	/**
	 * stores the information about the charcter's aboiliy the turn/rebuke
	 * undead
	 * 
	 * @author Jacob Palnick
	 * 
	 */
	public static class RebukeUndead {

		public int timesPerDay;
		public int turningCheck;
		public String turningDamage;

		public RebukeUndead() {
			timesPerDay = 0;
			turningCheck = 0;
			turningDamage = " ";
		}

		public RebukeUndead(Element rebukeUndeadElement) {
			timesPerDay = Integer.parseInt(rebukeUndeadElement.getFirstChildElement("timesPerDay").getValue());
			turningCheck = Integer.parseInt(rebukeUndeadElement.getFirstChildElement("turningCheck").getValue());
			turningDamage = rebukeUndeadElement.getFirstChildElement("turningDamage").getValue();
		}

		public Element getRebukeUndeadElement() {
			Element rebukeUndeadElement = new Element("rebukeUndead");

			Element timesPerDayElement = new Element("timesPerDay");
			timesPerDayElement.appendChild("" + timesPerDay);
			rebukeUndeadElement.appendChild(timesPerDayElement);

			Element turningCheckElement = new Element("turningCheck");
			turningCheckElement.appendChild("" + turningCheck);
			rebukeUndeadElement.appendChild(turningCheckElement);

			Element turningDamageElement = new Element("turningDamage");
			turningDamageElement.appendChild(turningDamage);
			rebukeUndeadElement.appendChild(turningDamageElement);

			return rebukeUndeadElement;
		}
	}

	public static class SpellsTable {

		public class SpellLevelInfo {
			public int level;
			public int spellsKnown;
			public int spellSaveDC;
			public int spellsPerDay;
			public int bonusSpells;
			public int remainingSpells;

			public int totalSpellsPerDay() {
				// TODO check that bonus spells add to the number of spells of
				// that level that can be used in a day
				return spellsPerDay + bonusSpells;
			}

			// TODO check method to reset remainingsSpells
			public void resetRemainingSpells() {
				remainingSpells = spellsPerDay + bonusSpells;
			}

			public SpellLevelInfo(int level) {
				this.level = level;
				spellsKnown = 0;
				spellSaveDC = 0;
				spellsPerDay = 0;
				bonusSpells = 0;
				remainingSpells = 0;
			}

			public SpellLevelInfo(Element spellLevelInfoElement) {
				level = Integer.parseInt(spellLevelInfoElement.getAttributeValue("level"));
				spellsKnown = Integer.parseInt(spellLevelInfoElement.getChildElements("spellsKnown").get(0).getValue());
				spellSaveDC = Integer.parseInt(spellLevelInfoElement.getChildElements("spellSaveDC").get(0).getValue());
				spellsPerDay = Integer.parseInt(spellLevelInfoElement.getChildElements("spellsPerDay").get(0).getValue());
				bonusSpells = Integer.parseInt(spellLevelInfoElement.getChildElements("bonusSpells").get(0).getValue());
				remainingSpells = Integer.parseInt(spellLevelInfoElement.getChildElements("remainingSpells").get(0).getValue());
			}

			public Element getSpellLevelInfoElement() {
				Element spellLevelInfoElement = new Element("spellLevelInfo");

				Attribute levelAttribute = new Attribute("level", "" + level);
				spellLevelInfoElement.addAttribute(levelAttribute);

				Element spellsKnownElement = new Element("spellsKnown");
				spellsKnownElement.appendChild("" + spellsKnown);
				spellLevelInfoElement.appendChild(spellsKnownElement);

				Element spellSaveDCElement = new Element("spellSaveDC");
				spellSaveDCElement.appendChild("" + spellSaveDC);
				spellLevelInfoElement.appendChild(spellSaveDCElement);

				Element spellsPerDayElement = new Element("spellsPerDay");
				spellsPerDayElement.appendChild("" + spellsPerDay);
				spellLevelInfoElement.appendChild(spellsPerDayElement);

				Element bonusSpellsElement = new Element("bonusSpells");
				bonusSpellsElement.appendChild("" + bonusSpells);
				spellLevelInfoElement.appendChild(bonusSpellsElement);

				Element remainingSpellsElement = new Element("remainingSpells");
				remainingSpellsElement.appendChild("" + remainingSpells);
				spellLevelInfoElement.appendChild(remainingSpellsElement);

				return spellLevelInfoElement;
			}
		}

		public int spellSave;
		public String conditionalModifiers;

		public SpellLevelInfo[] spellLevelInfo;

		// TODO check method to reset remaining spells for all levels
		public void resetAllRemainingSpells() {
			for (SpellLevelInfo lvInfo : spellLevelInfo) {
				lvInfo.resetRemainingSpells();
			}
		}

		public SpellsTable() {
			spellSave = 5;
			conditionalModifiers = " ";

			spellLevelInfo = new SpellLevelInfo[10];

			for (int index = 0; index < 10; index++) {
				spellLevelInfo[index] = new SpellLevelInfo(index);
			}
		}

		public SpellsTable(Element spellsTableElement) {
			spellSave = Integer.parseInt(spellsTableElement.getChildElements("spellSave").get(0).getValue());
			conditionalModifiers = spellsTableElement.getChildElements("conditionalModifiers").get(0).getValue();

			spellLevelInfo = new SpellLevelInfo[10];
			Elements levelElements = spellsTableElement.getChildElements("spellLevelInfo");

			for (int index = 0; index < levelElements.size(); index++) {
				int lv = Integer.parseInt(levelElements.get(index).getAttribute("level").getValue());
				spellLevelInfo[lv] = new SpellLevelInfo(levelElements.get(index));
			}
		}

		public Element getSpellsTableElement() {
			Element spellsTableElement = new Element("spellsTable");

			Element spellSaveElement = new Element("spellSave");
			spellSaveElement.appendChild("" + spellSave);
			spellsTableElement.appendChild(spellSaveElement);

			Element conditionalModifiersElement = new Element("conditionalModifiers");
			conditionalModifiersElement.appendChild(conditionalModifiers);
			spellsTableElement.appendChild(conditionalModifiersElement);

			for (SpellLevelInfo info : spellLevelInfo) {
				spellsTableElement.appendChild(info.getSpellLevelInfoElement());
			}

			return spellsTableElement;
		}
	}

	public class ArmorClass {

		public int sizeModifier;
		public int naturalArmor;
		public int deflectionModifier; // TODO check to see it there is just one
										// source of deflection
		public ModifierGroup miscModifier;

		public String specialDefense;

		public String armorName;
		public int armorMaxDex;
		public int armorCheckPenalty;
		public String armorWeight;
		public int armorBonus;

		public String shieldName;
		public int shieldMaxDex;
		public int shieldCheckPenalty;
		public String shieldWeight;
		public int shieldBonus;

		public int maxDex() {
			return Math.min(armorMaxDex, shieldMaxDex);
		}

		public int getArmorCheckPenalty() {
			return armorCheckPenalty + shieldCheckPenalty;
		}

		public int getTotal() {
			return 10 + armorBonus + shieldBonus + getAbilityModifier(Ability.DEXTERITY) + sizeModifier + naturalArmor + deflectionModifier
					+ miscModifier.getModifierSum();
		}

		public int getTouch() {
			return 10 + getAbilityModifier(Ability.DEXTERITY) + sizeModifier + deflectionModifier + miscModifier.getModifierSum();
		}

		public int getFlatFooted() {
			return 10 + armorBonus + shieldBonus + sizeModifier + naturalArmor + deflectionModifier + miscModifier.getModifierSum();
		}

		public ArmorClass() {
			sizeModifier = 0;
			naturalArmor = 0;
			deflectionModifier = 0;
			miscModifier = new ModifierGroup();

			specialDefense = " ";
			armorName = " ";
			armorMaxDex = 1000;
			armorCheckPenalty = 0;
			armorWeight = " ";
			armorBonus = 0;

			shieldName = " ";
			shieldMaxDex = 1000;
			shieldCheckPenalty = 0;
			shieldWeight = " ";
			shieldBonus = 0;
		}

		public ArmorClass(Element armorClassElement) {
			sizeModifier = Integer.parseInt(armorClassElement.getChildElements("sizeModifier").get(0).getValue());
			naturalArmor = Integer.parseInt(armorClassElement.getChildElements("naturalArmor").get(0).getValue());
			deflectionModifier = Integer.parseInt(armorClassElement.getChildElements("deflectionModifier").get(0).getValue());

			miscModifier = new ModifierGroup(armorClassElement.getChildElements("miscModifier").get(0).getChildElements());

			specialDefense = armorClassElement.getChildElements("specialDefense").get(0).getValue();

			armorName = armorClassElement.getChildElements("armorName").get(0).getValue();
			armorMaxDex = Integer.parseInt(armorClassElement.getChildElements("armorMaxDex").get(0).getValue());
			armorCheckPenalty = Integer.parseInt(armorClassElement.getChildElements("armorCheckPenalty").get(0).getValue());
			armorWeight = armorClassElement.getChildElements("armorWeight").get(0).getValue();
			armorBonus = Integer.parseInt(armorClassElement.getChildElements("armorBonus").get(0).getValue());

			shieldName = armorClassElement.getChildElements("shieldName").get(0).getValue();
			shieldMaxDex = Integer.parseInt(armorClassElement.getChildElements("shieldMaxDex").get(0).getValue());
			shieldCheckPenalty = Integer.parseInt(armorClassElement.getChildElements("shieldCheckPenalty").get(0).getValue());
			shieldWeight = armorClassElement.getChildElements("shieldWeight").get(0).getValue();
			shieldBonus = Integer.parseInt(armorClassElement.getChildElements("shieldBonus").get(0).getValue());

		}

		public Element getArmorClassElement() {
			Element armorClassElement = new Element("armorClass");

			Element sizeModifierElement = new Element("sizeModifier");
			sizeModifierElement.appendChild("" + sizeModifier);
			armorClassElement.appendChild(sizeModifierElement);

			Element naturalArmorElement = new Element("naturalArmor");
			naturalArmorElement.appendChild("" + naturalArmor);
			armorClassElement.appendChild(naturalArmorElement);

			Element deflectionModifierElement = new Element("deflectionModifier");
			deflectionModifierElement.appendChild("" + deflectionModifier);
			armorClassElement.appendChild(deflectionModifierElement);

			armorClassElement.appendChild(miscModifier.getModifierGroupElement("miscModifier"));

			armorClassElement.appendChild(makeSimpleElement("specialDefense", specialDefense));

			Element armorNameElement = new Element("armorName");
			armorNameElement.appendChild(armorName);
			armorClassElement.appendChild(armorNameElement);

			Element armorMaxDexElement = new Element("armorMaxDex");
			armorMaxDexElement.appendChild("" + armorMaxDex);
			armorClassElement.appendChild(armorMaxDexElement);

			Element armorCheckPenaltyElement = new Element("armorCheckPenalty");
			armorCheckPenaltyElement.appendChild("" + armorCheckPenalty);
			armorClassElement.appendChild(armorCheckPenaltyElement);

			Element armorWeightElement = new Element("armorWeight");
			armorWeightElement.appendChild(armorWeight);
			armorClassElement.appendChild(armorWeightElement);

			Element armorBonusElement = new Element("armorBonus");
			armorBonusElement.appendChild("" + armorBonus);
			armorClassElement.appendChild(armorBonusElement);

			Element shieldNameElement = new Element("shieldName");
			shieldNameElement.appendChild(shieldName);
			armorClassElement.appendChild(shieldNameElement);

			Element shieldMaxDexElement = new Element("shieldMaxDex");
			shieldMaxDexElement.appendChild("" + shieldMaxDex);
			armorClassElement.appendChild(shieldMaxDexElement);

			Element shieldCheckPenaltyElement = new Element("shieldCheckPenalty");
			shieldCheckPenaltyElement.appendChild("" + shieldCheckPenalty);
			armorClassElement.appendChild(shieldCheckPenaltyElement);

			Element shieldWeightElement = new Element("shieldWeight");
			shieldWeightElement.appendChild(shieldWeight);
			armorClassElement.appendChild(shieldWeightElement);

			Element shieldBonusElement = new Element("shieldBonus");
			shieldBonusElement.appendChild("" + shieldBonus);
			armorClassElement.appendChild(shieldBonusElement);

			return armorClassElement;
		}
	}

	public class SavingThrowConditional {

		public class Conditional {

			public SavingThrow savingThrow;
			public String requirements;
			public int value;

			public Conditional(SavingThrow savingThrow, String requirements, int value) {
				this.requirements = requirements;
				this.savingThrow = savingThrow;
				this.value = value;
			}

			public Conditional(Element conditionalElement) {
				savingThrow = SavingThrow.valueOf(conditionalElement.getChildElements("savingThrow").get(0).getValue());

				requirements = conditionalElement.getChildElements("requirements").get(0).getValue();

				value = Integer.parseInt(conditionalElement.getChildElements("value").get(0).getValue());
			}

			public Element getConditionalElement() {
				Element conditionalElement = new Element("conditional");

				Element savingThrowElement = new Element("savingThrow");
				savingThrowElement.appendChild(savingThrow.name());
				conditionalElement.appendChild(savingThrowElement);

				Element requirementElement = new Element("requirements");
				requirementElement.appendChild(requirements);
				conditionalElement.appendChild(requirementElement);

				Element valueElement = new Element("value");
				valueElement.appendChild("" + value);
				conditionalElement.appendChild(valueElement);

				return conditionalElement;
			}
		}

		public Conditional[] conditionals;

		public Conditional[] getConditionalsFor(SavingThrow savingThrow) {
			int count = 0;
			for (int index = 0; index < conditionals.length; index++) {
				if (conditionals[index].savingThrow.equals(savingThrow)) {
					count++;
				}
			}

			Conditional[] out = new Conditional[count];

			count = 0;

			for (int index = 0; index < conditionals.length; index++) {
				if (conditionals[index].savingThrow.equals(savingThrow)) {
					out[count] = conditionals[index];
					count++;
				}
			}

			return out;
		}

		public void addConditional(SavingThrow savingThrow, String requirements, int value) {
			if (conditionals != null) {
				Conditional[] tmp = conditionals;

				conditionals = new Conditional[tmp.length + 1];

				System.arraycopy(tmp, 0, conditionals, 0, tmp.length);

				conditionals[tmp.length] = new Conditional(savingThrow, requirements, value);
			} else {
				conditionals = new Conditional[1];
				conditionals[0] = new Conditional(savingThrow, requirements, value);
			}
		}

		public void removeConditional(SavingThrow savingThrow, String requirements) {
			if (conditionals != null) {
				int index = -1;

				for (int number = 0; number < conditionals.length && index == -1; number++) {
					if (conditionals[number].savingThrow.equals(savingThrow) && conditionals[number].requirements.equals(requirements)) {
						index = number;
					}
				}

				if (index != -1) {
					if (conditionals.length > 1) {
						Conditional[] tmp = conditionals;

						conditionals = new Conditional[tmp.length - 1];

						System.arraycopy(tmp, 0, conditionals, 0, index);
						System.arraycopy(tmp, index + 1, conditionals, index, tmp.length - index - 1);
					} else {
						conditionals = null;
					}
				}
			}
		}

		public SavingThrowConditional() {
			conditionals = null;
		}

		public SavingThrowConditional(Elements savingThrowConditionalElements) {
			int numberOfConditionals = savingThrowConditionalElements.size();
			if (numberOfConditionals > 0) {
				conditionals = new Conditional[numberOfConditionals];

				for (int index = 0; index < numberOfConditionals; index++) {
					conditionals[index] = new Conditional(savingThrowConditionalElements.get(index));
				}
			} else {
				conditionals = null;
			}
		}

		public Element getSavingThrowConditinalElement() {
			Element savingThrowConditionalElement = new Element("savingThrowConditionals");

			if (conditionals != null) {
				for (Conditional conditional : conditionals) {
					savingThrowConditionalElement.appendChild(conditional.getConditionalElement());
				}
			}

			return savingThrowConditionalElement;
		}
	}

	public class SavingThrowData {

		public int baseSave;
		public Ability ability;
		public ModifierGroup magicModifier;
		public ModifierGroup miscModifier;
		public ModifierGroup temporaryModifier;

		public int total() {
			return baseSave + getAbilityModifier(ability) + magicModifier.getModifierSum() + miscModifier.getModifierSum()
					+ temporaryModifier.getModifierSum();
		}

		public SavingThrowData(Ability keyAbility) {
			ability = keyAbility;
			baseSave = 0;
			miscModifier = new ModifierGroup();
			magicModifier = new ModifierGroup();
			temporaryModifier = new ModifierGroup();
		}

		public SavingThrowData(Element savingThrowDataElement) {
			baseSave = Integer.parseInt(savingThrowDataElement.getChildElements("baseSave").get(0).getValue());

			ability = Ability.valueOf(savingThrowDataElement.getChildElements("ability").get(0).getValue());

			magicModifier = new ModifierGroup(savingThrowDataElement.getChildElements("magicModifier").get(0).getChildElements());
			miscModifier = new ModifierGroup(savingThrowDataElement.getChildElements("miscModifier").get(0).getChildElements());
			temporaryModifier = new ModifierGroup(savingThrowDataElement.getChildElements("temporaryModifier").get(0).getChildElements());

		}

		public Element getSavingThrowElement() {
			Element savingThrowElement;
			if (ability == Ability.CONSTITUTION) {
				savingThrowElement = new Element("fortitude");
			} else if (ability == Ability.DEXTERITY) {
				savingThrowElement = new Element("reflex");
			} else {
				savingThrowElement = new Element("will");
			}

			Element baseSaveElement = new Element("baseSave");
			baseSaveElement.appendChild("" + baseSave);
			savingThrowElement.appendChild(baseSaveElement);

			Element abilityElement = new Element("ability");
			abilityElement.appendChild(ability.name());
			savingThrowElement.appendChild(abilityElement);

			savingThrowElement.appendChild(magicModifier.getModifierGroupElement("magicModifier"));
			savingThrowElement.appendChild(miscModifier.getModifierGroupElement("miscModifier"));
			savingThrowElement.appendChild(temporaryModifier.getModifierGroupElement("temporaryModifier"));

			return savingThrowElement;
		}
	}

	public class CharacterClass {

		public String className;
		public int classLevel;

		// TODO remove CharacterClass() when done testing
		public CharacterClass() {
			className = " ";
			classLevel = 0;
		}

		public CharacterClass(String className, int classLevel) {
			this.classLevel = classLevel;
			this.className = className;
		}

		public CharacterClass(String className) {
			this.className = className;
			classLevel = 1;
		}

		public String getStringFormat() {
			return className + " - " + classLevel;
		}
	}

	public class Attack {

		public String weaponName;
		public int weaponAttackBonus;
		public String damage;
		public int minimumRollForCritical;
		public int criticalMultiplier;
		public int rangeIncrement;
		public String weaponType;
		public String notes;
		public int ammo;
		public boolean requiresAmmo;

		public Attack() {
			weaponName = " ";
			weaponAttackBonus = 0;
			damage = " ";
			minimumRollForCritical = 20;
			criticalMultiplier = 1;
			rangeIncrement = 0;
			weaponType = " ";
			notes = " ";
			ammo = 0;
			requiresAmmo = false;
		}

		public Attack(Element attackElement) {
			weaponName = attackElement.getChildElements("weaponName").get(0).getValue();

			weaponAttackBonus = Integer.parseInt(attackElement.getChildElements("weaponAttackBonus").get(0).getValue());
			damage = attackElement.getChildElements("damage").get(0).getValue();
			minimumRollForCritical = Integer.parseInt(attackElement.getChildElements("minimumRollForCritical").get(0).getValue());
			criticalMultiplier = Integer.parseInt(attackElement.getChildElements("criticalMultiplier").get(0).getValue());
			rangeIncrement = Integer.parseInt(attackElement.getChildElements("rangeIncrement").get(0).getValue());
			weaponType = attackElement.getChildElements("weaponType").get(0).getValue();
			notes = attackElement.getChildElements("notes").get(0).getValue();
			ammo = Integer.parseInt(attackElement.getChildElements("ammo").get(0).getValue());
			requiresAmmo = Boolean.parseBoolean(attackElement.getChildElements("requiresAmmo").get(0).getValue());

		}

		public Element getAttackElement() {
			Element attackElement = new Element("attack");

			Element weaponNameElement = new Element("weaponName");
			weaponNameElement.appendChild(weaponName);
			attackElement.appendChild(weaponNameElement);

			Element weaponAttackBonusElement = new Element("weaponAttackBonus");
			weaponAttackBonusElement.appendChild("" + weaponAttackBonus);
			attackElement.appendChild(weaponAttackBonusElement);

			Element damageElement = new Element("damage");
			damageElement.appendChild(damage);
			attackElement.appendChild(damageElement);

			Element minimumRollForCriticalElement = new Element("minimumRollForCritical");
			minimumRollForCriticalElement.appendChild("" + minimumRollForCritical);
			attackElement.appendChild(minimumRollForCriticalElement);

			Element criticalMultiplierElement = new Element("criticalMultiplier");
			criticalMultiplierElement.appendChild("" + criticalMultiplier);
			attackElement.appendChild(criticalMultiplierElement);

			Element rangeIncrementElement = new Element("rangeIncrement");
			rangeIncrementElement.appendChild("" + rangeIncrement);
			attackElement.appendChild(rangeIncrementElement);

			Element weaponTypeElement = new Element("weaponType");
			weaponTypeElement.appendChild(weaponType);
			attackElement.appendChild(weaponTypeElement);

			Element notesElement = new Element("notes");
			notesElement.appendChild(notes);
			attackElement.appendChild(notesElement);

			Element ammoElement = new Element("ammo");
			ammoElement.appendChild("" + ammo);
			attackElement.appendChild(ammoElement);

			Element requiresAmmoElement = new Element("requiresAmmo");
			if (requiresAmmo) {
				requiresAmmoElement.appendChild("true");
			} else {
				requiresAmmoElement.appendChild("false");
			}
			attackElement.appendChild(requiresAmmoElement);

			return attackElement;
		}
	}

	public class BaseAttackBonus {

		private int attackBonus;

		public int numberOfAttacksPerTurn() {
			return (attackBonus + 5) / 5;
		}

		public int baseAttackBonus(int attackNumber) {
			return attackBonus - 5 * attackNumber;
		}

		public String baseAttackBonusString() {
			String out = "+" + attackBonus;
			for (int number = 1; number < numberOfAttacksPerTurn(); number++) {
				out = out + "/+" + (attackBonus - 5 * number);
			}
			return out;
		}

		public void setMaxAttackBonus(int maxBonus) {
			attackBonus = maxBonus;
		}

		public BaseAttackBonus(Element baseAttackBonusElement) {
			attackBonus = Integer.parseInt(baseAttackBonusElement.getChildElements("attackBonus").get(0).getValue());

		}

		public Element getBaseAttackBonusElement() {
			Element baseAttackBonusElement = new Element("baseAttackBonus");

			Element attackBonusElement = new Element("attackBonus");
			attackBonusElement.appendChild("" + attackBonus);
			baseAttackBonusElement.appendChild(attackBonusElement);

			return baseAttackBonusElement;
		}

		public BaseAttackBonus(int maxAttackBonus) {
			attackBonus = maxAttackBonus;
		}

		public BaseAttackBonus() {
			attackBonus = 1;
		}
	}

	public class GrappleModifer {

		public int sizeModifer;
		public ModifierGroup miscModifers;

		public GrappleModifer(Element grappleModifierElement) {
			sizeModifer = Integer.parseInt(grappleModifierElement.getChildElements("sizeModifier").get(0).getValue());

			miscModifers = new ModifierGroup(grappleModifierElement.getChildElements("miscModifiers").get(0).getChildElements());

		}

		public Element getGrappleModifierElement() {
			Element grappleModifierElement = new Element("grappleModifier");

			Element sizeModifierElement = new Element("sizeModifier");
			sizeModifierElement.appendChild("" + sizeModifer);
			grappleModifierElement.appendChild(sizeModifierElement);

			grappleModifierElement.appendChild(miscModifers.getModifierGroupElement("miscModifiers"));

			return grappleModifierElement;
		}

		public int total(int actionNumber) {
			return baseAttackBonus.baseAttackBonus(actionNumber) + strength.getModifier() + sizeModifer + miscModifers.getModifierSum();
		}

		private String appendSign(int number) {
			if (number > 0) {
				return "+" + number;
			} else if (number < 0) {
				return "-" + number;
			} else {
				return "0";
			}
		}

		public String getTotalString() {
			String out = appendSign(total(0));
			for (int number = 1; number < baseAttackBonus.numberOfAttacksPerTurn(); number++) {
				out = out + "/" + appendSign(total(number));
			}
			return out;
		}

		public GrappleModifer() {
			sizeModifer = 0;
			miscModifers = new ModifierGroup();
		}
	}

	public class Modifier {

		public String modifierDescription;
		public int modifierValue;
		
		//TODO add field to specifiy if the modifier only applies to special conditions

		public Modifier(Element modifierElement) {
			this.modifierDescription = modifierElement.getChildElements("modifierDescription").get(0).getValue();
			this.modifierValue = Integer.parseInt(modifierElement.getChildElements("modifierValue").get(0).getValue());
		}

		public Modifier(String modiferDescription, int modifierValue) {
			this.modifierDescription = modiferDescription;
			this.modifierValue = modifierValue;

		}

		public Element getModifierElement() {
			Element modifierElement = new Element("modifier");
			Element modifierDescriptionElement = new Element("modifierDescription");
			modifierDescriptionElement.appendChild(modifierDescription);
			modifierElement.appendChild(modifierDescriptionElement);
			Element modifierValueElement = new Element("modifierValue");
			modifierValueElement.appendChild("" + modifierValue);
			modifierElement.appendChild(modifierValueElement);

			return modifierElement;
		}

		public String getStringFormat() {
			return modifierDescription + " (" + modifierValue + ")";
		}

	}

	public class ModifierGroup {

		public Modifier[] modifiers;

		public ModifierGroup(Elements modifierGroupElements) {
			if (modifierGroupElements.size() > 0) {
				modifiers = new Modifier[modifierGroupElements.size()];

				for (int index = 0; index < modifierGroupElements.size(); index++) {
					modifiers[index] = new Modifier(modifierGroupElements.get(index));
				}
			} else {
				modifiers = null;
			}
		}

		public Element getModifierGroupElement(String elementName) {
			Element modifierGroupElement = new Element(elementName);

			if (modifiers != null) {
				for (Modifier modifier : modifiers) {
					modifierGroupElement.appendChild(modifier.getModifierElement());
				}
			}

			return modifierGroupElement;
		}

		public ModifierGroup() {
			modifiers = new Modifier[1];
			modifiers[0] = new Modifier("test", 0);
		}

		public void addModifier(String modifierDescription, int modifierValue) {
			if (modifiers != null) {
				Modifier[] tmp = modifiers;

				modifiers = new Modifier[tmp.length + 1];

				System.arraycopy(tmp, 0, modifiers, 0, tmp.length);

				modifiers[tmp.length] = new Modifier(modifierDescription, modifierValue);

				tmp = null;
			} else {
				modifiers = new Modifier[1];
				modifiers[0] = new Modifier(modifierDescription, modifierValue);
			}
		}

		public int findIndexOfModifer(String modifierDescription) {
			int index = -1;
			for (int modifierIndex = 0; modifierIndex < modifiers.length && index == -1; modifierIndex++) {
				if (modifiers[modifierIndex].modifierDescription.equals(modifierDescription)) {
					index = modifierIndex;
				}
			}

			return index;
		}

		public void removeModifer(String modifierDescription) {
			if (modifiers != null) {
				int index = findIndexOfModifer(modifierDescription);

				if (index != -1) {
					if (modifiers.length > 1) {
						Modifier[] tmp = modifiers;

						modifiers = new Modifier[tmp.length - 1];

						System.arraycopy(tmp, 0, modifiers, 0, index);
						System.arraycopy(tmp, index + 1, modifiers, index, tmp.length - index - 1);

						tmp = null;
					} else {
						modifiers = null;
					}
				}
			}
		}

		public void editModifierDescription(int modifierIndex, String newDescription) {
			
		}
		
		public String getStringForModifier(String modifierDescription) {
			int index = findIndexOfModifer(modifierDescription);

			String output = "";

			if (index != -1) {
				output = modifiers[index].getStringFormat();
			}

			return output;
		}

		public String getStringFormat() {
			String output = "";

			for (int index = 0; index < modifiers.length; index++) {
				output = output + modifiers[index].getStringFormat();
				if (index < modifiers.length - 1) {
					output = output + System.getProperty("line.separator");
				}
			}

			return output;
		}

		public int getModifierSum() {
			int sum = 0;
			for (int index = 0; index < modifiers.length; index++) {
				sum += modifiers[index].modifierValue;
			}

			return sum;
		}

	}

	public class AbilityScore {

		public int baseScore;
		public ModifierGroup enhancementBonuses;
		public ModifierGroup miscModifiers;
		private Ability ability;

		public AbilityScore(Element abilityScoreElement) {
			this.ability = Ability.valueOf(abilityScoreElement.getLocalName().toUpperCase());

			this.baseScore = Integer.parseInt(abilityScoreElement.getChildElements("baseScore").get(0).getValue());

			this.enhancementBonuses = new ModifierGroup(abilityScoreElement.getChildElements("enhancementBonuses").get(0)
					.getChildElements());
			this.miscModifiers = new ModifierGroup(abilityScoreElement.getChildElements("miscModifiers").get(0).getChildElements());

		}

		public Element getAbilityScoreElement() {
			Element abilityScoreElement = new Element(ability.name().toLowerCase());

			Element baseScoreElement = new Element("baseScore");
			baseScoreElement.appendChild("" + baseScore);
			abilityScoreElement.appendChild(baseScoreElement);

			abilityScoreElement.appendChild(enhancementBonuses.getModifierGroupElement("enhancementBonuses"));
			abilityScoreElement.appendChild(miscModifiers.getModifierGroupElement("miscModifiers"));

			return abilityScoreElement;
		}

		// TODO remove when done testing
		public void setAbility(Ability ability) {
			this.ability = ability;
		}

		public int total() {
			int total = baseScore;

			for (int enhancementIndex = 0; enhancementIndex < enhancementBonuses.modifiers.length; enhancementIndex++) {
				total = total + enhancementBonuses.modifiers[enhancementIndex].modifierValue;
			}

			for (int miscIndex = 0; miscIndex < miscModifiers.modifiers.length; miscIndex++) {
				total = total + miscModifiers.modifiers[miscIndex].modifierValue;
			}

			return total;
		}

		public int getModifier() {
			return (total() - 10) / 2;
		}

		public AbilityScore() {
			baseScore = 0;
			enhancementBonuses = new ModifierGroup();
			miscModifiers = new ModifierGroup();
		}

		public AbilityScore(Ability ability) {
			baseScore = 0;
			enhancementBonuses = new ModifierGroup();
			miscModifiers = new ModifierGroup();
			this.ability = ability;
		}
	}

	public class CharacterClasses {

		public CharacterClass[] classes;

		public CharacterClasses() {
			classes = new CharacterClass[1];
			classes[0] = new CharacterClass();

		}

		public CharacterClasses(Element characterClassesElement) {
			Elements characterClassesElements = characterClassesElement.getChildElements();

			int numberOfElements = characterClassesElements.size();

			classes = new CharacterClass[numberOfElements];

			for (int index = 0; index < numberOfElements; index++) {
				String tmpName = characterClassesElements.get(index).getChildElements("className").get(0).getValue();
				int tmpLv = Integer.parseInt(characterClassesElements.get(index).getChildElements("classLevel").get(0).getValue());
				classes[index] = new CharacterClass(tmpName, tmpLv);
			}
		}

		public Element getCharacterClassesElement() {
			Element characterClassesElement = new Element("characterClasses");
			for (int index = 0; index < classes.length; index++) {
				Element characterClassElement = new Element("characterClass");
				Element className = new Element("className");
				className.appendChild(classes[index].className);
				characterClassElement.appendChild(className);
				Element classLevel = new Element("classLevel");
				classLevel.appendChild("" + classes[index].classLevel);
				characterClassElement.appendChild(classLevel);

				characterClassesElement.appendChild(characterClassElement);
			}

			return characterClassesElement;
		}

		public void addClass(String className) {
			if (classes != null) {
				CharacterClass[] tmp = classes;

				classes = new CharacterClass[tmp.length + 1];

				System.arraycopy(tmp, 0, classes, 0, tmp.length);

				classes[tmp.length] = new CharacterClass(className);
			} else {
				classes = new CharacterClass[1];

				classes[0] = new CharacterClass(className);
			}
		}

		public void levelUpClass(String className) {
			boolean foundClass = false;

			for (int classIndex = 0; classIndex < classes.length && !foundClass; classIndex++) {
				if (classes[classIndex].className.equals(className)) {
					foundClass = true;
					classes[classIndex].classLevel++;
				}
			}
		}
	}

	public class Psionics {
		public int numberOfPowersKnown;
		public int maxPowerLevelKnown;
		public String primaryDiscipline;
		public int powerPointsPerDay;
		public int currentPowerPoints;

		public void resetPowerPoints() {
			currentPowerPoints = 0;
		}

		public Psionics() {
			numberOfPowersKnown = 0;
			maxPowerLevelKnown = 0;
			primaryDiscipline = " ";
			powerPointsPerDay = 0;
			currentPowerPoints = 0;
		}

		public Psionics(Element psionicsElement) {
			numberOfPowersKnown = Integer.parseInt(psionicsElement.getFirstChildElement("numberOfPowersKnown").getValue());
			maxPowerLevelKnown = Integer.parseInt(psionicsElement.getFirstChildElement("maxPowerLevelKnown").getValue());
			primaryDiscipline = psionicsElement.getFirstChildElement("primaryDiscipline").getValue();
			powerPointsPerDay = Integer.parseInt(psionicsElement.getFirstChildElement("powerPointsPerDay").getValue());
			currentPowerPoints = Integer.parseInt(psionicsElement.getFirstChildElement("currentPowerPoints").getValue());
		}

		public Element getPsionicsElement() {
			Element psionicsElement = new Element("psionics");

			psionicsElement.appendChild(makeSimpleElement("numberOfPowersKnown", numberOfPowersKnown));
			psionicsElement.appendChild(makeSimpleElement("maxPowerLevelKnown", maxPowerLevelKnown));
			psionicsElement.appendChild(makeSimpleElement("primaryDiscipline", primaryDiscipline));
			psionicsElement.appendChild(makeSimpleElement("powerPointsPerDay", powerPointsPerDay));
			psionicsElement.appendChild(makeSimpleElement("currentPowerPoints", currentPowerPoints));

			return psionicsElement;
		}
	}

	public class Rage {
		public int ragesPerDay;
		public String duration;
		public int abilityBonus; // TODO check how the ability bonus works for
									// rage
		public int willBonus; // TODO check how the will save bonus works for
								// rage
		public int acPenalty;
		public int ragesUsed;
		public int roundsElapsed;
		public boolean inRage;

		public Rage() {
			ragesPerDay = 0;
			duration = " ";
			abilityBonus = 0;
			willBonus = 0;
			acPenalty = 0;
			ragesUsed = 0;
			roundsElapsed = 0;
			inRage = false;
		}

		public Rage(Element rageElement) {
			ragesPerDay = getElementIntValue(rageElement, "ragesPerDay");
			duration = getElementValue(rageElement, "duration");
			abilityBonus = getElementIntValue(rageElement, "abilityBonus");
			willBonus = getElementIntValue(rageElement, "willBonus");
			acPenalty = getElementIntValue(rageElement, "acPenalty");
			ragesUsed = getElementIntValue(rageElement, "ragesUsed");
			roundsElapsed = getElementIntValue(rageElement, "roundsElapsed");
			inRage = Boolean.parseBoolean(getElementValue(rageElement, "inRage"));
		}

		public Element getRageElement() {
			Element rageElement = new Element("rage");

			rageElement.appendChild(makeSimpleElement("ragesPerDay", ragesPerDay));
			rageElement.appendChild(makeSimpleElement("duration", duration));
			rageElement.appendChild(makeSimpleElement("abilityBonus", abilityBonus));
			rageElement.appendChild(makeSimpleElement("willBonus", willBonus));
			rageElement.appendChild(makeSimpleElement("acPenalty", acPenalty));
			rageElement.appendChild(makeSimpleElement("ragesUsed", ragesUsed));
			rageElement.appendChild(makeSimpleElement("roundsElapsed", roundsElapsed));
			if (inRage) {
				rageElement.appendChild(makeSimpleElement("inRage", "true"));
			} else {
				rageElement.appendChild(makeSimpleElement("inRage", "false"));
			}

			return rageElement;
		}

	}

	public class AnimalCompanion {
		public String name;
		public String creatureType;
		public int strength;
		public int dexterity;
		public int constitution;
		public int intelligence;
		public int wisdom;
		public int charisma;
		public int initiativeModifier;
		public int speed;
		public int maxHP;
		public int currentHP;
		public int sizeModifier;
		public int naturalArmor;
		public ModifierGroup miscACModifiers;
		public int fortitude;
		public int reflex;
		public int will;
		public AnimalAttack attack1;
		public AnimalAttack attack2;
		public AnimalAttack attack3;

		public int grappleModifier;
		public String personality;
		public AnimalSkill[] skills;
		public AnimalFeat[] feats;
		public AnimalSpecialAbility[] specialAbilities;
		public AnimalTrick[] tricks;

		public AnimalCompanion() {
			name = " ";
			creatureType = " ";
			strength = 0;
			dexterity = 0;
			constitution = 0;
			intelligence = 0;
			wisdom = 0;
			charisma = 0;
			initiativeModifier = 0;
			speed = 30;
			maxHP = 20;
			currentHP = 20;
			sizeModifier = 0;
			naturalArmor = 0;
			miscACModifiers = new ModifierGroup();
			fortitude = 0;
			reflex = 0;
			will = 0;
			attack1 = new AnimalAttack();
			attack2 = new AnimalAttack();
			attack3 = new AnimalAttack();
			grappleModifier = 0;
			personality = " ";
			skills = null;
			feats = null;
			specialAbilities = null;
			tricks = null;
		}

		public AnimalCompanion(Element animalCompanionElement) {
			name = getElementValue(animalCompanionElement, "name");
			creatureType = getElementValue(animalCompanionElement, "creatureType");
			strength = getElementIntValue(animalCompanionElement, "strength");
			dexterity = getElementIntValue(animalCompanionElement, "dexterity");
			constitution = getElementIntValue(animalCompanionElement, "constitution");
			intelligence = getElementIntValue(animalCompanionElement, "intelligence");
			wisdom = getElementIntValue(animalCompanionElement, "wisdom");
			charisma = getElementIntValue(animalCompanionElement, "charisma");
			initiativeModifier = getElementIntValue(animalCompanionElement, "initiativeModifier");
			speed = getElementIntValue(animalCompanionElement, "speed");
			maxHP = getElementIntValue(animalCompanionElement, "maxHP");
			currentHP = getElementIntValue(animalCompanionElement, "currentHP");
			sizeModifier = getElementIntValue(animalCompanionElement, "sizeModifier");
			naturalArmor = getElementIntValue(animalCompanionElement, "naturalArmor");
			miscACModifiers = new ModifierGroup(animalCompanionElement.getFirstChildElement("miscACModifiers").getChildElements());
			fortitude = getElementIntValue(animalCompanionElement, "fortitude");
			reflex = getElementIntValue(animalCompanionElement, "reflex");
			will = getElementIntValue(animalCompanionElement, "will");
			attack1 = new AnimalAttack(animalCompanionElement.getFirstChildElement("attack1").getFirstChildElement("animalAttack"));
			attack2 = new AnimalAttack(animalCompanionElement.getFirstChildElement("attack2").getFirstChildElement("animalAttack"));
			attack3 = new AnimalAttack(animalCompanionElement.getFirstChildElement("attack3").getFirstChildElement("animalAttack"));
			grappleModifier = getElementIntValue(animalCompanionElement, "grappleModifier");
			personality = getElementValue(animalCompanionElement, "personality");
			Elements skillsElements = animalCompanionElement.getFirstChildElement("skills").getChildElements();
			if (skillsElements.size() > 0) {
				skills = new AnimalSkill[skillsElements.size()];

				for (int i = 0; i < skillsElements.size(); i++) {
					skills[i] = new AnimalSkill(skillsElements.get(i));
				}
			} else {
				skills = null;
			}

			Elements featsElements = animalCompanionElement.getFirstChildElement("feats").getChildElements();
			if (featsElements.size() > 0) {
				feats = new AnimalFeat[featsElements.size()];

				for (int i = 0; i < featsElements.size(); i++) {
					feats[i] = new AnimalFeat(featsElements.get(i));
				}
			} else {
				feats = null;
			}

			Elements specialAbilitiesElements = animalCompanionElement.getFirstChildElement("specialAbilities").getChildElements();
			if (specialAbilitiesElements.size() > 0) {
				specialAbilities = new AnimalSpecialAbility[specialAbilitiesElements.size()];

				for (int i = 0; i < specialAbilitiesElements.size(); i++) {
					specialAbilities[i] = new AnimalSpecialAbility(specialAbilitiesElements.get(i));
				}
			} else {
				specialAbilities = null;
			}

			Elements tricksElements = animalCompanionElement.getFirstChildElement("tricks").getChildElements();
			if (tricksElements.size() > 0) {
				tricks = new AnimalTrick[tricksElements.size()];

				for (int i = 0; i < tricksElements.size(); i++) {
					tricks[i] = new AnimalTrick(tricksElements.get(i));
				}
			} else {
				tricks = null;
			}

		}

		public Element getAnimalCompanionElement() {
			Element animalCompanionElement = new Element("animalCompanion");

			animalCompanionElement.appendChild(makeSimpleElement("name", name));
			animalCompanionElement.appendChild(makeSimpleElement("creatureType", creatureType));
			animalCompanionElement.appendChild(makeSimpleElement("strength", strength));
			animalCompanionElement.appendChild(makeSimpleElement("dexterity", dexterity));
			animalCompanionElement.appendChild(makeSimpleElement("constitution", constitution));
			animalCompanionElement.appendChild(makeSimpleElement("intelligence", intelligence));
			animalCompanionElement.appendChild(makeSimpleElement("wisdom", wisdom));
			animalCompanionElement.appendChild(makeSimpleElement("charisma", charisma));
			animalCompanionElement.appendChild(makeSimpleElement("initiativeModifier", initiativeModifier));
			animalCompanionElement.appendChild(makeSimpleElement("speed", speed));
			animalCompanionElement.appendChild(makeSimpleElement("maxHP", maxHP));
			animalCompanionElement.appendChild(makeSimpleElement("currentHP", currentHP));
			animalCompanionElement.appendChild(makeSimpleElement("sizeModifier", sizeModifier));
			animalCompanionElement.appendChild(makeSimpleElement("naturalArmor", naturalArmor));
			animalCompanionElement.appendChild(miscACModifiers.getModifierGroupElement("miscACModifiers"));
			animalCompanionElement.appendChild(makeSimpleElement("fortitude", fortitude));
			animalCompanionElement.appendChild(makeSimpleElement("reflex", reflex));
			animalCompanionElement.appendChild(makeSimpleElement("will", will));

			Element attack1Element = new Element("attack1");
			attack1Element.appendChild(attack1.getAnimalAttackElement());
			animalCompanionElement.appendChild(attack1Element);

			Element attack2Element = new Element("attack2");
			attack2Element.appendChild(attack2.getAnimalAttackElement());
			animalCompanionElement.appendChild(attack2Element);

			Element attack3Element = new Element("attack3");
			attack3Element.appendChild(attack3.getAnimalAttackElement());
			animalCompanionElement.appendChild(attack3Element);

			animalCompanionElement.appendChild(makeSimpleElement("grappleModifier", grappleModifier));
			animalCompanionElement.appendChild(makeSimpleElement("personality", personality));

			Element skillsElement = new Element("skills");
			if (skills != null) {
				for (AnimalSkill skill : skills) {
					skillsElement.appendChild(skill.getAnimalSkillElement());
				}
			}
			animalCompanionElement.appendChild(skillsElement);

			Element featsElement = new Element("feats");
			if (feats != null) {
				for (AnimalFeat feat : feats) {
					featsElement.appendChild(feat.getAnimalFeatElemnt());
				}
			}
			animalCompanionElement.appendChild(featsElement);

			Element specialAbilitiesElement = new Element("specialAbilities");
			if (specialAbilities != null) {
				for (AnimalSpecialAbility specialAbility : specialAbilities) {
					specialAbilitiesElement.appendChild(specialAbility.getAnimalSpecialAbilityElement());
				}
			}
			animalCompanionElement.appendChild(specialAbilitiesElement);

			Element tricksElement = new Element("tricks");
			if (tricks != null) {
				for (AnimalTrick trick : tricks) {
					tricksElement.appendChild(trick.getAnimalTrickElement());
				}
			}
			animalCompanionElement.appendChild(tricksElement);

			return animalCompanionElement;
		}

		public int totalAC() {
			return 10 + Character.this.dexterity.getModifier() + sizeModifier + naturalArmor + miscACModifiers.getModifierSum();
		}

		public int touchAC() {
			return 10 + Character.this.dexterity.getModifier() + sizeModifier + miscACModifiers.getModifierSum();
		}

		public int flatfootedAC() {
			return 10 + sizeModifier + naturalArmor + miscACModifiers.getModifierSum();
		}

		public class AnimalAttack {
			public String weapon;
			public String attackBonus;
			public String damage;
			public String critical;

			public AnimalAttack() {
				weapon = " ";
				attackBonus = " ";
				damage = " ";
				critical = " ";
			}

			public AnimalAttack(Element animalAttackElement) {
				weapon = getElementValue(animalAttackElement, "weapon");
				attackBonus = getElementValue(animalAttackElement, "attackBonus");
				damage = getElementValue(animalAttackElement, "damage");
				critical = getElementValue(animalAttackElement, "critical");
			}

			public Element getAnimalAttackElement() {
				Element aniamlAttackElement = new Element("animalAttack");

				aniamlAttackElement.appendChild(makeSimpleElement("weapon", weapon));
				aniamlAttackElement.appendChild(makeSimpleElement("attackBonus", attackBonus));
				aniamlAttackElement.appendChild(makeSimpleElement("damage", damage));
				aniamlAttackElement.appendChild(makeSimpleElement("critical", critical));

				return aniamlAttackElement;
			}
		}

		public class AnimalSkill {
			public String skill;
			public int value;

			public AnimalSkill() {
				skill = " ";
				value = 0;
			}

			public AnimalSkill(String skillName, int value) {
				this.skill = skillName;
				this.value = value;
			}

			public AnimalSkill(Element animalSkillElement) {
				skill = getElementValue(animalSkillElement, "skill");
				value = getElementIntValue(animalSkillElement, "value");
			}

			public Element getAnimalSkillElement() {
				Element animalSkillElement = new Element("animalSkill");

				animalSkillElement.appendChild(makeSimpleElement("skill", skill));
				animalSkillElement.appendChild(makeSimpleElement("value", value));

				return animalSkillElement;
			}
		}

		public class AnimalFeat {
			public String featName;
			public String description;

			public AnimalFeat() {
				featName = " ";
				description = " ";
			}

			public AnimalFeat(String featName, String description) {
				this.featName = featName;
				this.description = description;
			}

			public AnimalFeat(Element animalFeatElement) {
				featName = getElementValue(animalFeatElement, "featName");
				description = getElementValue(animalFeatElement, "description");
			}

			public Element getAnimalFeatElemnt() {
				Element animalFeatElement = new Element("animalFeat");

				animalFeatElement.appendChild(makeSimpleElement("featName", featName));
				animalFeatElement.appendChild(makeSimpleElement("description", description));

				return animalFeatElement;
			}
		}

		public class AnimalSpecialAbility {
			public String specialAbility;
			public String description;

			public AnimalSpecialAbility() {
				specialAbility = " ";
				description = " ";
			}

			public AnimalSpecialAbility(String specialAbility, String description) {
				this.specialAbility = specialAbility;
				this.description = description;
			}

			public AnimalSpecialAbility(Element animalSpecialAbilityElement) {
				specialAbility = getElementValue(animalSpecialAbilityElement, "specialAbility");
				description = getElementValue(animalSpecialAbilityElement, "description");
			}

			public Element getAnimalSpecialAbilityElement() {
				Element animalSpecialAbilityElement = new Element("animalSpecialAbility");

				animalSpecialAbilityElement.appendChild(makeSimpleElement("specialAbility", specialAbility));
				animalSpecialAbilityElement.appendChild(makeSimpleElement("description", description));

				return animalSpecialAbilityElement;
			}
		}

		public class AnimalTrick {
			public String trick;
			public String description;

			public AnimalTrick() {
				trick = " ";
				description = " ";
			}

			public AnimalTrick(String trick, String description) {
				this.trick = trick;
				this.description = description;
			}

			public AnimalTrick(Element animalTrickElement) {
				trick = getElementValue(animalTrickElement, "trick");
				description = getElementValue(animalTrickElement, "description");
			}

			public Element getAnimalTrickElement() {
				Element animalTrickElement = new Element("animalTrick");

				animalTrickElement.appendChild(makeSimpleElement("trick", trick));
				animalTrickElement.appendChild(makeSimpleElement("description", description));

				return animalTrickElement;
			}
		}

		public int getSkillIndex(String skillName) {
			if (skills != null) {
				int index = -1;

				for (int i = 0; i < skills.length && index == -1; i++) {
					if (skills[i].skill.equals(skillName)) {
						index = i;
					}
				}

				return index;
			}
			return -1;
		}

		public int getFeatIndex(String featName) {
			if (feats != null) {
				int index = -1;

				for (int i = 0; i < feats.length && index == -1; i++) {
					if (feats[i].featName.equals(featName)) {
						index = i;
					}
				}
				return index;
			}
			return -1;
		}

		public int getSpecialAbilityIndex(String name) {
			if (specialAbilities != null) {
				int index = -1;

				for (int i = 0; i < specialAbilities.length && index == -1; i++) {
					if (specialAbilities[i].specialAbility.equals(name)) {
						index = i;
					}
				}
				return index;
			}
			return -1;
		}

		public int getTrickIndex(String trick) {
			if (tricks != null) {
				int index = -1;
				for (int i = 0; i < tricks.length && index == -1; i++) {
					if (tricks[i].trick.equals(trick)) {
						index = i;
					}
				}
				return index;
			}
			return -1;
		}

		// TODO should i add methods to remove feat/skill/specialAbility/trick?

		public void addSkill(AnimalSkill newSkill) {
			if (skills != null) {
				if (getSkillIndex(newSkill.skill) != -1) {
					// TODO figure out how to deal with trying to add a skill
					// that already exists
				} else {
					AnimalSkill[] tmp = skills;

					skills = new AnimalSkill[tmp.length + 1];
					System.arraycopy(tmp, 0, skills, 0, tmp.length);

					skills[tmp.length] = newSkill;
				}
			} else {
				skills = new AnimalSkill[1];
				skills[0] = newSkill;
			}
		}

		public void addSkill(String skillName, int value) {
			addSkill(new AnimalSkill(skillName, value));
		}

		public void addFeat(AnimalFeat newFeat) {
			if (feats != null) {
				if (getFeatIndex(newFeat.featName) == -1) {
					AnimalFeat[] tmp = feats;

					feats = new AnimalFeat[tmp.length + 1];
					System.arraycopy(tmp, 0, feats, 0, tmp.length);
					feats[tmp.length] = newFeat;
				}
			} else {
				feats = new AnimalFeat[1];
				feats[0] = newFeat;
			}
		}

		public void addFeat(String featName, String description) {
			addFeat(new AnimalFeat(featName, description));
		}

		public void addSpecialAbility(AnimalSpecialAbility newSpecialAbility) {
			if (specialAbilities != null) {
				if (getSpecialAbilityIndex(newSpecialAbility.specialAbility) == -1) {
					AnimalSpecialAbility[] tmp = specialAbilities;

					specialAbilities = new AnimalSpecialAbility[tmp.length + 1];

					System.arraycopy(tmp, 0, specialAbilities, 0, tmp.length);

					specialAbilities[tmp.length] = newSpecialAbility;
				}
			} else {
				specialAbilities = new AnimalSpecialAbility[1];
				specialAbilities[0] = newSpecialAbility;
			}
		}

		public void addSpecialAbility(String specialAbility, String description) {
			addSpecialAbility(new AnimalSpecialAbility(specialAbility, description));
		}

		public void addTrick(AnimalTrick newTrick) {
			if (tricks != null) {
				if (getTrickIndex(newTrick.trick) == -1) {
					AnimalTrick[] tmp = tricks;

					tricks = new AnimalTrick[tmp.length + 1];
					System.arraycopy(tmp, 0, tricks, 0, tmp.length);
					tricks[tmp.length] = newTrick;
				}
			} else {
				tricks = new AnimalTrick[1];
				tricks[0] = newTrick;
			}
		}

		public void addTrick(String trick, String description) {
			addTrick(new AnimalTrick(trick, description));
		}

	}

	public class Skill {
		public String skillName;
		public String skillFocus;
		public boolean canUseUntrained;
		public boolean hasArmorCheckPenalty;
		public Ability keyAbility;
		public int ranks;
		public ModifierGroup miscModifier;

		public int skillModifier() {
			if (hasArmorCheckPenalty) {
				if (skillName.toLowerCase().contains("swim")) {
					return getAbilityModifier(keyAbility) + ranks + miscModifier.getModifierSum() - (getArmorCheckPenalty() * 2);
				} else {
					return getAbilityModifier(keyAbility) + ranks + miscModifier.getModifierSum() - getArmorCheckPenalty();
				}
			} else {
				return getAbilityModifier(keyAbility) + ranks + miscModifier.getModifierSum();
			}
		}

		public Skill() {
			skillName = " ";
			skillFocus = " ";
			canUseUntrained = false;
			hasArmorCheckPenalty = false;
			keyAbility = Ability.CHARISMA;
			ranks = 0;
			miscModifier = new ModifierGroup();
		}

		public Skill(String name, String focus, boolean canUseUntrained, boolean hasArmorCheckPenalty, Ability keyAbility, int ranks) {
			this.skillName = name;
			this.skillFocus = focus;
			this.canUseUntrained = canUseUntrained;
			this.hasArmorCheckPenalty = hasArmorCheckPenalty;
			this.keyAbility = keyAbility;
			this.ranks = ranks;
			miscModifier = new ModifierGroup();
		}

		public Skill(String name, String focus, boolean canUseUntrained, boolean hasArmorCheckPenalty, Ability keyAbility, int ranks,
				ModifierGroup miscModifier) {
			this.skillName = name;
			this.skillFocus = focus;
			this.canUseUntrained = canUseUntrained;
			this.hasArmorCheckPenalty = hasArmorCheckPenalty;
			this.keyAbility = keyAbility;
			this.ranks = ranks;
			this.miscModifier = miscModifier;
		}

		public Skill(Element skillElement) {
			skillName = getElementValue(skillElement, "skillName");
			skillFocus = getElementValue(skillElement, "skillFocus");
			canUseUntrained = getElementBoolValue(skillElement, "canUseUntrained");
			hasArmorCheckPenalty = getElementBoolValue(skillElement, "hasArmorCheckPenalty");
			keyAbility = Ability.valueOf(getElementValue(skillElement, "keyAbility"));
			ranks = getElementIntValue(skillElement, "ranks");
			miscModifier = new ModifierGroup(skillElement.getFirstChildElement("miscModifiers").getChildElements());
		}

		public Element getSkillElement() {
			Element skillElement = new Element("skill");

			skillElement.appendChild(makeSimpleElement("skillName", skillName));
			skillElement.appendChild(makeSimpleElement("skillFocus", skillFocus));
			skillElement.appendChild(makeSimpleElement("canUseUntrained", canUseUntrained));
			skillElement.appendChild(makeSimpleElement("hasArmorCheckPenalt", hasArmorCheckPenalty));
			skillElement.appendChild(makeSimpleElement("keyAbility", keyAbility.name()));
			skillElement.appendChild(makeSimpleElement("ranks", ranks));
			skillElement.appendChild(miscModifier.getModifierGroupElement("miscModifiers"));

			return skillElement;
		}

	}

	// TODO check SkillList
	public class SkillList {

		public Skill[] skills;

		public SkillList() {
			skills = null;
		}

		public SkillList(Element skillListElement) {
			if (skillListElement.getChildElements().size() > 0) {
				Elements skillsElements = skillListElement.getChildElements();
				skills = new Skill[skillsElements.size()];

				for (int i = 0; i < skillsElements.size(); i++) {
					skills[i] = new Skill(skillsElements.get(i));
				}
			} else {
				skills = null;
			}
		}

		public int getSkillIndex(String name) {
			if (skills != null) {
				int index = -1;

				for (int i = 0; i < skills.length && index == -1; i++) {
					if (skills[i].skillName.equalsIgnoreCase(name)) {// &&
																		// !skills[i].skillFocus.matches("\\s*\\S*\\s*"))
																		// {
						index = i;
					}
				}
				return index;
			}
			return -1;
		}

		public int getSkillIndex(String name, String focus) {
			if (skills != null) {
				int index = -1;

				for (int i = 0; i < skills.length && index == -1; i++) {
					if (skills[i].skillName.equals(name) && skills[i].skillFocus.equalsIgnoreCase(focus)) {
						index = i;
					}
				}
				return index;
			}
			return -1;
		}

		public Skill getSkill(String name) {
			int index = getSkillIndex(name);
			if (index != -1) {
				return skills[index];
			}
			return null;
		}

		public Skill getSkill(String name, String focus) {
			int index = getSkillIndex(name, focus);
			if (index != -1) {
				return skills[index];
			}
			return null;
		}

		public void addSkill(Skill newSkill) {
			if (skills != null) {
				if (newSkill.skillFocus.matches("\\s*\\S*\\s*")) {
					boolean found = false;
					for (int i = 0; i < skills.length && !found; i++) {
						if (skills[i].skillName.equalsIgnoreCase(newSkill.skillName)
								&& skills[i].skillFocus.toLowerCase().contains(newSkill.skillFocus.toLowerCase())) {
							found = true;
						}
					}

					if (!found) {
						Skill[] tmp = skills;

						skills = new Skill[tmp.length + 1];
						System.arraycopy(tmp, 0, skills, 0, tmp.length);
						skills[tmp.length] = newSkill;
					}
				} else {
					if (getSkillIndex(newSkill.skillName) == -1) {
						Skill[] tmp = skills;

						skills = new Skill[tmp.length + 1];
						System.arraycopy(tmp, 0, skills, 0, tmp.length);
						skills[tmp.length] = newSkill;
					}
				}
			} else {
				skills = new Skill[1];
				skills[0] = newSkill;
			}
		}

		public void setSkillRanks(String skillName, int ranks) {
			int index = getSkillIndex(skillName);
			if (index != -1) {
				skills[index].ranks = ranks;
			}
		}

		public void setSkillRanks(String skillName, String skillFocus, int ranks) {
			int index = getSkillIndex(skillName, skillFocus);
			if (index != -1) {
				skills[index].ranks = ranks;
			}
		}

		public Element getSkillListElement() {
			Element skillListElement = new Element("skillList");

			if (skills != null) {
				for (Skill skill : skills) {
					skillListElement.appendChild(skill.getSkillElement());
				}
			}

			return skillListElement;
		}

	}

	// TODO check RacialTrait
	public class RacialTrait {
		public String traitName;
		public String description;

		public RacialTrait() {
			traitName = " ";
			description = " ";
		}

		public RacialTrait(Element racialTraitElement) {
			traitName = getElementValue(racialTraitElement, "traitName");
			description = getElementValue(racialTraitElement, "description");
		}

		public RacialTrait(String trait, String description) {
			this.traitName = trait;
			this.description = description;
		}

		public Element getRacialTraitElement() {
			Element racialTraitElement = new Element("racialTrait");

			racialTraitElement.appendChild(makeSimpleElement("traitName", traitName));
			racialTraitElement.appendChild(makeSimpleElement("description", description));

			return racialTraitElement;
		}

	}

	// TODO check ClassFeature
	public class ClassFeature {
		public String featureName;
		public String description;

		public ClassFeature() {
			featureName = " ";
			description = " ";
		}

		public ClassFeature(String featureName, String description) {
			this.featureName = featureName;
			this.description = description;
		}

		public ClassFeature(Element classFeatureElement) {
			featureName = getElementValue(classFeatureElement, "featureName");
			description = getElementValue(classFeatureElement, "description");
		}

		public Element getClassFeatureElement() {
			Element classFeatureElement = new Element("classFeature");

			classFeatureElement.appendChild(makeSimpleElement("featureName", featureName));
			classFeatureElement.appendChild(makeSimpleElement("description", description));

			return classFeatureElement;
		}

	}

	// TODO check Feat
	public class Feat {
		public String featName;
		public String description;

		public Feat() {
			featName = " ";
			description = " ";
		}

		public Feat(String featName, String description) {
			this.featName = featName;
			this.description = description;
		}

		public Feat(Element featElement) {
			featName = getElementValue(featElement, "featName");
			description = getElementValue(featElement, "description");
		}

		public Element getFeatElement() {
			Element featElement = new Element("feat");

			featElement.appendChild(makeSimpleElement("featName", featName));
			featElement.appendChild(makeSimpleElement("description", description));

			return featElement;
		}

	}

	// TODO finish Language
	public class Language {
		public String languageName;
		public String description;

		public Language() {
			languageName = " ";
			description = " ";
		}

		public Language(String languageName, String description) {
			this.languageName = languageName;
			this.description = description;
		}

		public Language(Element languageElement) {
			languageName = getElementValue(languageElement, "languageName");
			description = getElementValue(languageElement, "description");
		}

		public Element getLanguageElement() {
			Element languageElement = new Element("lanaguage");

			languageElement.appendChild(makeSimpleElement("languageName", languageName));
			languageElement.appendChild(makeSimpleElement("description", description));

			return languageElement;
		}

	}

	public static class Spell {
		public static enum SpellFields {
			LEVEL, NAME, DESCRIPTION, SCHOOL, CASTING_TIME, RANGE, TARGETS, DURATION, SAVING_THROW, EFFECTS
		};

		public int level;
		public String name;
		public String description;
		public String school;
		public String castingTime;
		public String range;
		public String targets;
		public String duration;
		public SavingThrow savingThrow;
		public String effects;

		public Spell() {
			level = 0;
			name = " ";
			description = " ";
			school = " ";
			castingTime = " ";
			range = " ";
			targets = " ";
			duration = " ";
			savingThrow = SavingThrow.FORTITUDE;
			effects = " ";
		}

		public Spell(Element spellElement) {
			level = getElementIntValue(spellElement, "level");
			name = getElementValue(spellElement, "name");
			description = getElementValue(spellElement, "description");
			school = getElementValue(spellElement, "school");
			castingTime = getElementValue(spellElement, "castingTime");
			range = getElementValue(spellElement, "range");
			targets = getElementValue(spellElement, "targets");
			duration = getElementValue(spellElement, "duration");
			savingThrow = SavingThrow.valueOf(getElementValue(spellElement, "savingThrow"));
			effects = getElementValue(spellElement, "effects");
		}

		public Element getSpellElement() {
			Element spellElement = new Element("spell");

			spellElement.appendChild(makeSimpleElement("level", level));
			spellElement.appendChild(makeSimpleElement("name", name));
			spellElement.appendChild(makeSimpleElement("description", description));
			spellElement.appendChild(makeSimpleElement("school", school));
			spellElement.appendChild(makeSimpleElement("castingTime", castingTime));
			spellElement.appendChild(makeSimpleElement("range", range));
			spellElement.appendChild(makeSimpleElement("targets", targets));
			spellElement.appendChild(makeSimpleElement("duration", duration));
			spellElement.appendChild(makeSimpleElement("savingThrow", savingThrow.name()));
			spellElement.appendChild(makeSimpleElement("effects", effects));

			return spellElement;
		}

	}

	public class SpellList {
		public Spell[] spellList;

		public SpellList() {
			spellList = null;
		}

		public SpellList(Element spellsElement) {
			Elements spellElements = spellsElement.getChildElements();

			if (spellElements.size() > 0) {
				spellList = new Spell[spellElements.size()];
				for (int i = 0; i < spellList.length; i++) {
					spellList[i] = new Spell(spellElements.get(i));
				}
			} else {
				spellList = null;
			}
		}

		public int getSpellIndexByName(String name) {
			if (spellList != null) {

				for (int i = 0; i < spellList.length; i++) {
					if (spellList[i].name.equalsIgnoreCase(name)) {
						return i;
					}
				}
			}

			return -1;
		}

		public Spell[] getSpellsOfLevel(int level) {
			List<Spell> resultSpellList = new ArrayList<Character.Spell>();
			for (Spell spell : spellList) {
				if (spell.level == level) {
					resultSpellList.add(spell);
				}
			}

			Spell[] results = (Spell[]) resultSpellList.toArray();
			resultSpellList = null;

			return results;
		}

		public Spell[] getSpellsWithString(String searchFor) {
			List<Spell> resultList = new ArrayList<Spell>();
			for (Spell spell : spellList) {
				if (spell.name.toLowerCase().contains(searchFor) || spell.description.toLowerCase().contains(searchFor)
						|| spell.school.toLowerCase().contains(searchFor) || spell.castingTime.toLowerCase().contains(searchFor)
						|| spell.range.toLowerCase().contains(searchFor) || spell.targets.toLowerCase().contains(searchFor)
						|| spell.duration.toLowerCase().contains(searchFor) || spell.savingThrow.name().contains(searchFor)
						|| spell.effects.toLowerCase().contains(searchFor)) {
					resultList.add(spell);
				}
			}

			Spell[] results = resultList.toArray(new Spell[0]);
			resultList = null;

			return results;
		}

		// TODO implement a method to seach for spells that contain a specified
		// string in specific fields
		/*
		 * public Spell[] searchSpells(String searchString, SpellFields
		 * fieldsToSearch) { List<Spell> matchingSpellList = new
		 * ArrayList<Spell>();
		 * 
		 * for(Spell spell : spellList) { if(((fieldsToSearch &
		 * SpellFields.CASTING_TIME) == SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch & SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString.toLowerCase()))
		 * && ((fieldsToSearch && SpellFields.CASTING_TIME) ==
		 * SpellFields.CASTING_TIME &&
		 * spell.castingTime.toLowerCase().contains(searchString
		 * .toLowerCase()))) } } //
		 */

		public void addSpell(Spell newSpell) {
			if (spellList != null) {
				int index = getSpellIndexByName(newSpell.name);

				if (index != -1) {
					Spell[] tmp = spellList;
					spellList = new Spell[tmp.length + 1];

					System.arraycopy(tmp, 0, spellList, 0, tmp.length);
					spellList[tmp.length] = newSpell;
				}
			} else {
				spellList = new Spell[1];
				spellList[0] = newSpell;
			}
		}

		public Element getSpellListElement() {
			Element spellListElement = new Element("spellList");

			if (spellList != null) {
				for (Spell spell : spellList) {
					spellListElement.appendChild(spell.getSpellElement());
				}
			}

			return spellListElement;
		}

	}

	public static class Power {
		public String name;
		public String description;
		public int powerPointCost;

		public Power() {
			name = " ";
			description = " ";
			powerPointCost = 0;
		}

		public Power(Element powerElement) {
			name = getElementValue(powerElement, "name");
			description = getElementValue(powerElement, "description");
			powerPointCost = getElementIntValue(powerElement, "powerPointCost");
		}

		public Power(String name, String description, int powerPointCost) {
			this.name = name;
			this.description = description;
			this.powerPointCost = powerPointCost;
		}

		public Element getPowerElement() {
			Element powerElement = new Element("power");

			powerElement.appendChild(makeSimpleElement("name", name));
			powerElement.appendChild(makeSimpleElement("description", description));
			powerElement.appendChild(makeSimpleElement("powerPointCost", powerPointCost));

			return powerElement;
		}

	}

	public class PowerList {
		public Power[] powerList;

		public PowerList() {
			powerList = null;
		}

		public PowerList(Element powerListElement) {
			Elements powersElement = powerListElement.getChildElements();
			if (powersElement.size() > 0) {
				powerList = new Power[powersElement.size()];
				for (int i = 0; i < powersElement.size(); i++) {
					powerList[i] = new Power(powersElement.get(i));
				}
			}
		}

		public Element getPowerListElement() {
			Element powerListElement = new Element("powerList");

			if (powerList != null) {
				for (Power power : powerList) {
					powerListElement.appendChild(power.getPowerElement());
				}
			}

			return powerListElement;
		}

		// TODO implement search functions like for SpellList

		public void addPower(Power newPower) {
			if (powerList.length > 0) {
				if (true) { // TODO check if the power already exists to prevent
							// duplicates
					Power[] tmp = powerList;
					powerList = new Power[tmp.length + 1];

					System.arraycopy(tmp, 0, powerList, 0, tmp.length);
					powerList[tmp.length] = newPower;
				}
			} else {
				powerList = new Power[1];
				powerList[0] = newPower;
			}
		}

	}

	// variables

	public String characterName;
	public CharacterClasses characterClasses;
	public String race;
	public String size;
	public String gender;
	public String alignment;
	public String religion;
	public String deity;
	public String height;
	public String weight;
	public String looks;

	public AbilityScore strength;
	public AbilityScore dexterity;
	public AbilityScore constitution;
	public AbilityScore intelligence;
	public AbilityScore wisdom;
	public AbilityScore charisma;

	public BaseAttackBonus baseAttackBonus;
	public Attack attack1;
	public Attack attack2;
	public Attack attack3;
	public Attack attack4;

	public int speed;
	public int initiativeModifier;

	public GrappleModifer grappleModifier;

	public SavingThrowData fortitude;
	public SavingThrowData reflex;
	public SavingThrowData will;
	public SavingThrowConditional savingThrowConditionalModifiers;

	public int maxHP;
	public int currentHP;
	public int nonlethalDamage;

	public ArmorClass AC;

	public int experiancePoints;

	public int lightLoad;
	public int mediumLoad;
	public int heavyLoad;

	public Money money;

	public Possession[] possessionsOnPerson;
	public Possession[] possessionsNotOnPerson;
	public MagicItems magicItemsWorn;

	public Magic magic;

	public RebukeUndead rebukeUndead;

	public SpellsTable spellsTable;

	public Psionics psionics;

	public Rage rage;

	public AnimalCompanion animalCompanion;

	public SkillList skillList;

	public RacialTrait[] racialTaits;

	public ClassFeature[] classFeatures;

	public Feat[] feats;

	public Language[] languages;

	public PowerList powers;

	public SpellList spells;

	// methods

	// TODO check that the add/remove/edit(replace) possession methods work
	public void addPossessionOnPerson(Possession newPossession) {
		Possession[] tmp = possessionsOnPerson;

		possessionsOnPerson = new Possession[tmp.length + 1];

		System.arraycopy(tmp, 0, possessionsOnPerson, 0, tmp.length);

		possessionsOnPerson[tmp.length] = newPossession;
	}

	public void addPossessionNotOnPerson(Possession newPossession) {
		Possession[] tmp = possessionsNotOnPerson;

		possessionsNotOnPerson = new Possession[tmp.length + 1];

		System.arraycopy(tmp, 0, possessionsNotOnPerson, 0, tmp.length);

		possessionsNotOnPerson[tmp.length] = newPossession;
	}

	public void removePossessionOnPerson(Possession possessionToRemove) {
		if (possessionsOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsOnPerson.length && index == -1; number++) {
				if (possessionsOnPerson[number] == possessionToRemove) {
					index = number;
				}
			}

			if (index != -1) {
				if (possessionsOnPerson.length > 1) {
					Possession[] tmp = possessionsOnPerson;

					possessionsOnPerson = new Possession[tmp.length - 1];

					System.arraycopy(tmp, 0, possessionsOnPerson, 0, index);

					System.arraycopy(tmp, index + 1, possessionsOnPerson, index, tmp.length - index - 1);
				} else {
					possessionsOnPerson = null;
				}
			}
		}
	}

	public void removePossessionOnPerson(String nameOfPossessionToRemove) {
		if (possessionsOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsOnPerson.length && index == -1; number++) {
				if (possessionsOnPerson[number].itemName.equals(nameOfPossessionToRemove)) {
					index = number;
				}
			}

			if (index != -1) {
				if (possessionsOnPerson.length > 1) {
					Possession[] tmp = possessionsOnPerson;

					possessionsOnPerson = new Possession[tmp.length - 1];

					System.arraycopy(tmp, 0, possessionsOnPerson, 0, index);

					System.arraycopy(tmp, index + 1, possessionsOnPerson, index, tmp.length - index - 1);
				} else {
					possessionsOnPerson = null;
				}
			}
		}
	}

	public void removePossessionNotOnPerson(Possession possessionToRemove) {
		if (possessionsNotOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsNotOnPerson.length && index == -1; number++) {
				if (possessionsNotOnPerson[number] == possessionToRemove) {
					index = number;
				}
			}

			if (index != -1) {
				if (possessionsNotOnPerson.length > 1) {
					Possession[] tmp = possessionsNotOnPerson;

					possessionsNotOnPerson = new Possession[tmp.length - 1];

					System.arraycopy(tmp, 0, possessionsNotOnPerson, 0, index);

					System.arraycopy(tmp, index + 1, possessionsNotOnPerson, index, tmp.length - index - 1);
				} else {
					possessionsNotOnPerson = null;
				}
			}
		}
	}

	public void removePossessionNotOnPerson(String nameOfPossessionToRemove) {
		if (possessionsNotOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsNotOnPerson.length && index == -1; number++) {
				if (possessionsNotOnPerson[number].itemName.equals(nameOfPossessionToRemove)) {
					index = number;
				}
			}

			if (index != -1) {
				if (possessionsNotOnPerson.length > 1) {
					Possession[] tmp = possessionsNotOnPerson;

					possessionsNotOnPerson = new Possession[tmp.length - 1];

					System.arraycopy(tmp, 0, possessionsNotOnPerson, 0, index);

					System.arraycopy(tmp, index + 1, possessionsNotOnPerson, index, tmp.length - index - 1);
				} else {
					possessionsNotOnPerson = null;
				}
			}
		}
	}

	public void editQuantityOfPossessionOnPerson(String nameOfPossessionToEdit, int newQuantity) {
		if (possessionsOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsOnPerson.length && index == -1; number++) {
				if (possessionsOnPerson[number].itemName.equals(nameOfPossessionToEdit)) {
					index = number;
					possessionsOnPerson[index].quantity = newQuantity;
				}
			}
		}
	}

	public void replacePossessionOnPerson(String nameOfPossessionToEdit, Possession newPossession) {
		if (possessionsOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsOnPerson.length && index == -1; number++) {
				if (possessionsOnPerson[number].itemName.equals(nameOfPossessionToEdit)) {
					index = number;
					possessionsOnPerson[index] = newPossession;
				}
			}
		}
	}

	public void replacePossessionNotOnPerson(String nameOfPossessionToEdit, Possession newPossession) {
		if (possessionsNotOnPerson != null) {
			int index = -1;

			for (int number = 0; number < possessionsNotOnPerson.length && index == -1; number++) {
				if (possessionsNotOnPerson[number].itemName.equals(nameOfPossessionToEdit)) {
					index = number;
					possessionsNotOnPerson[index] = newPossession;
				}
			}
		}
	}

	public int getAbilityModifier(Ability ability) {
		int modifier = 0;
		switch (ability) {
		case STRENGTH:
			modifier = strength.getModifier();
			break;
		case DEXTERITY:
			modifier = dexterity.getModifier();
			break;
		case CONSTITUTION:
			modifier = constitution.getModifier();
			break;
		case INTELLIGENCE:
			modifier = intelligence.getModifier();
			break;
		case WISDOM:
			modifier = wisdom.getModifier();
			break;
		case CHARISMA:
			modifier = charisma.getModifier();
			break;
		default:
			modifier = 0;
			break;
		}

		return modifier;
	}
	public AbilityScore getAbility(Ability ability) {
		AbilityScore abilityScore;
		switch (ability) {
		case STRENGTH:
			abilityScore = strength;
			break;
		case DEXTERITY:
			abilityScore = dexterity;
			break;
		case CONSTITUTION:
			abilityScore = constitution;
			break;
		case INTELLIGENCE:
			abilityScore = intelligence;
			break;
		case WISDOM:
			abilityScore = wisdom;
			break;
		case CHARISMA:
			abilityScore = charisma;
			break;
		default:
			abilityScore = null;
			break;
		}

		return abilityScore;
	}

	public int getArmorCheckPenalty() {
		return AC.getArmorCheckPenalty();
	}

	public Element newRoot;

	public void addToRoot(String elementName, String value) {
		Element tmp = new Element(elementName);
		tmp.appendChild(value);
		newRoot.appendChild(tmp);
	}

	public void addToRoot(String elementName, int value) {
		addToRoot(elementName, "" + value);
	}

	public void saveCharacterXML(File saveFile) {
		newRoot = new Element("character");
		addToRoot("characterName", characterName);
		newRoot.appendChild(characterClasses.getCharacterClassesElement());
		addToRoot("race", race);
		addToRoot("size", size);
		addToRoot("gender", gender);
		addToRoot("alignment", alignment);
		addToRoot("religion", religion);
		addToRoot("deity", deity);
		addToRoot("height", height);
		addToRoot("weight", weight);
		addToRoot("looks", looks);

		newRoot.appendChild(strength.getAbilityScoreElement());
		newRoot.appendChild(dexterity.getAbilityScoreElement());
		newRoot.appendChild(constitution.getAbilityScoreElement());
		newRoot.appendChild(intelligence.getAbilityScoreElement());
		newRoot.appendChild(wisdom.getAbilityScoreElement());
		newRoot.appendChild(charisma.getAbilityScoreElement());

		newRoot.appendChild(baseAttackBonus.getBaseAttackBonusElement());
		newRoot.appendChild(attack1.getAttackElement());
		newRoot.appendChild(attack2.getAttackElement());
		newRoot.appendChild(attack3.getAttackElement());
		newRoot.appendChild(attack4.getAttackElement());

		addToRoot("speed", speed);
		addToRoot("initiativeModifier", initiativeModifier);

		newRoot.appendChild(grappleModifier.getGrappleModifierElement());

		newRoot.appendChild(fortitude.getSavingThrowElement());
		newRoot.appendChild(reflex.getSavingThrowElement());
		newRoot.appendChild(will.getSavingThrowElement());
		newRoot.appendChild(savingThrowConditionalModifiers.getSavingThrowConditinalElement());

		addToRoot("maxHP", maxHP);
		addToRoot("currentHP", currentHP);
		addToRoot("nonlethalDamage", nonlethalDamage);

		newRoot.appendChild(AC.getArmorClassElement());

		addToRoot("experiancePoints", experiancePoints);

		addToRoot("lightLoad", lightLoad);
		addToRoot("mediumLoad", mediumLoad);
		addToRoot("heavyLoad", heavyLoad);

		newRoot.appendChild(money.getMoneyElement());

		Element possessionsOnPersonElement = new Element("possessionsOnPerson");

		for (int index = 0; index < possessionsOnPerson.length; index++) {
			possessionsOnPersonElement.appendChild(possessionsOnPerson[index].getPossesionElement());
		}

		Element possessionsNotOnPersonElement = new Element("possessionsNotOnPerson");

		for (int index = 0; index < possessionsNotOnPerson.length; index++) {
			possessionsNotOnPersonElement.appendChild(possessionsNotOnPerson[index].getPossesionElement());
		}

		newRoot.appendChild(possessionsOnPersonElement);
		newRoot.appendChild(possessionsNotOnPersonElement);

		newRoot.appendChild(magicItemsWorn.getMagicItemsElement());

		newRoot.appendChild(magic.getMagicElement());

		newRoot.appendChild(rebukeUndead.getRebukeUndeadElement());

		newRoot.appendChild(spellsTable.getSpellsTableElement());

		newRoot.appendChild(psionics.getPsionicsElement());

		newRoot.appendChild(rage.getRageElement());

		newRoot.appendChild(animalCompanion.getAnimalCompanionElement());

		newRoot.appendChild(skillList.getSkillListElement());

		Element racialTraitsElement = new Element("racialTraits");
		// if(racialTaits.length > 0) {
		for (RacialTrait trait : racialTaits) {
			racialTraitsElement.appendChild(trait.getRacialTraitElement());
		}
		// }
		newRoot.appendChild(racialTraitsElement);

		Element classFeaturesElement = new Element("classFeatures");
		for (ClassFeature feature : classFeatures) {
			classFeaturesElement.appendChild(feature.getClassFeatureElement());
		}
		newRoot.appendChild(classFeaturesElement);

		Element featsElement = new Element("feats");
		for (Feat feat : feats) {
			featsElement.appendChild(feat.getFeatElement());
		}
		newRoot.appendChild(featsElement);

		Element languagesElement = new Element("languages");
		for (Language language : languages) {
			languagesElement.appendChild(language.getLanguageElement());
		}
		newRoot.appendChild(languagesElement);

		newRoot.appendChild(powers.getPowerListElement());

		newRoot.appendChild(spells.getSpellListElement());

		Document doc = new Document(newRoot);

		// TODO save the xml to a specified file. create new file if needed
		// System.out.println(doc.toXML());
		// System.out.println(doc.toString());
		try {
			System.out.println("saving file");
			OutputStream out = new FileOutputStream(saveFile);
			out = new BufferedOutputStream(out);
			Serializer serializer = new Serializer(out, "ISO-8859-1");
			serializer.write(doc);
			System.out.println("file Saved!");
		} catch (IOException ex) {
			System.err.println("This shouldn't happen for Latin-1!");
		}

	}

	public Character(File characterXmlFile) {
		Builder bulder = new Builder();

		try {
			System.out.println("parseing the contents of the file");

			Document doc = bulder.build(characterXmlFile);
			Element root = doc.getRootElement();

			this.characterName = root.getChildElements("characterName").get(0).getValue();
			this.characterClasses = new CharacterClasses(root.getChildElements("characterClasses").get(0));
			race = root.getChildElements("race").get(0).getValue();
			size = root.getChildElements("size").get(0).getValue();
			gender = root.getChildElements("gender").get(0).getValue();
			alignment = root.getChildElements("alignment").get(0).getValue();
			religion = root.getChildElements("religion").get(0).getValue();
			deity = root.getChildElements("deity").get(0).getValue();
			height = root.getChildElements("height").get(0).getValue();
			weight = root.getChildElements("weight").get(0).getValue();
			looks = root.getChildElements("looks").get(0).getValue();

			strength = new AbilityScore(root.getChildElements("strength").get(0));
			dexterity = new AbilityScore(root.getChildElements("dexterity").get(0));
			constitution = new AbilityScore(root.getChildElements("constitution").get(0));
			intelligence = new AbilityScore(root.getChildElements("intelligence").get(0));
			wisdom = new AbilityScore(root.getChildElements("wisdom").get(0));
			charisma = new AbilityScore(root.getChildElements("charisma").get(0));

			baseAttackBonus = new BaseAttackBonus(root.getChildElements("baseAttackBonus").get(0));
			attack1 = new Attack(root.getChildElements("attack").get(0));
			attack2 = new Attack(root.getChildElements("attack").get(1));
			attack3 = new Attack(root.getChildElements("attack").get(2));
			attack4 = new Attack(root.getChildElements("attack").get(3));

			speed = Integer.parseInt(root.getChildElements("speed").get(0).getValue());
			initiativeModifier = Integer.parseInt(root.getChildElements("initiativeModifier").get(0).getValue());

			grappleModifier = new GrappleModifer(root.getChildElements("grappleModifier").get(0));

			fortitude = new SavingThrowData(root.getChildElements("fortitude").get(0));
			reflex = new SavingThrowData(root.getChildElements("reflex").get(0));
			will = new SavingThrowData(root.getChildElements("will").get(0));
			savingThrowConditionalModifiers = new SavingThrowConditional(root.getFirstChildElement("savingThrowConditionals")
					.getChildElements());

			maxHP = Integer.parseInt(root.getChildElements("maxHP").get(0).getValue());
			currentHP = Integer.parseInt(root.getChildElements("currentHP").get(0).getValue());
			nonlethalDamage = Integer.parseInt(root.getChildElements("nonlethalDamage").get(0).getValue());

			AC = new ArmorClass(root.getChildElements("armorClass").get(0));

			experiancePoints = Integer.parseInt(root.getChildElements("experiancePoints").get(0).getValue());

			lightLoad = Integer.parseInt(root.getChildElements("lightLoad").get(0).getValue());
			mediumLoad = Integer.parseInt(root.getChildElements("mediumLoad").get(0).getValue());
			heavyLoad = Integer.parseInt(root.getChildElements("heavyLoad").get(0).getValue());

			money = new Money(root.getChildElements("money").get(0));

			Elements possessionsOnPersonElements = root.getChildElements("possessionsOnPerson").get(0).getChildElements();
			Elements possessionsNotOnPersonElements = root.getChildElements("possessionsNotOnPerson").get(0).getChildElements();

			int popCount = possessionsOnPersonElements.size();
			int pnopCount = possessionsNotOnPersonElements.size();

			possessionsOnPerson = new Possession[popCount];
			possessionsNotOnPerson = new Possession[pnopCount];

			for (int index = 0; index < popCount; index++) {
				possessionsOnPerson[index] = new Possession(possessionsOnPersonElements.get(index));
			}
			for (int index = 0; index < pnopCount; index++) {
				possessionsNotOnPerson[index] = new Possession(possessionsNotOnPersonElements.get(index));
			}

			magicItemsWorn = new MagicItems(root.getChildElements("magicItems").get(0));

			magic = new Magic(root.getChildElements("magic").get(0));

			rebukeUndead = new RebukeUndead(root.getFirstChildElement("rebukeUndead"));

			spellsTable = new SpellsTable(root.getChildElements("spellsTable").get(0));

			psionics = new Psionics(root.getFirstChildElement("psionics"));

			rage = new Rage(root.getFirstChildElement("rage"));

			animalCompanion = new AnimalCompanion(root.getFirstChildElement("animalCompanion"));

			skillList = new SkillList(root.getFirstChildElement("skillList"));

			Elements racialTraitsElements = root.getFirstChildElement("racialTraits").getChildElements();
			if (racialTraitsElements.size() > 0) {
				racialTaits = new RacialTrait[racialTraitsElements.size()];
				for (int i = 0; i < racialTaits.length; i++) {
					racialTaits[i] = new RacialTrait(racialTraitsElements.get(i));
				}
			} else {
				racialTaits = null;
			}

			Elements featsElements = root.getFirstChildElement("feats").getChildElements();
			if (featsElements.size() > 0) {
				feats = new Feat[featsElements.size()];
				for (int i = 0; i < feats.length; i++) {
					feats[i] = new Feat(featsElements.get(i));
				}
			} else {
				feats = null;
			}

			Elements classFeaturesElements = root.getFirstChildElement("classFeatures").getChildElements();
			if (classFeaturesElements.size() > 0) {
				classFeatures = new ClassFeature[classFeaturesElements.size()];
				for (int i = 0; i < classFeatures.length; i++) {
					classFeatures[i] = new ClassFeature(classFeaturesElements.get(i));
				}
			} else {
				classFeatures = null;
			}

			Elements languagesElements = root.getFirstChildElement("languages").getChildElements();
			if (racialTraitsElements.size() > 0) {
				languages = new Language[languagesElements.size()];
				for (int i = 0; i < languages.length; i++) {
					languages[i] = new Language(languagesElements.get(i));
				}
			} else {
				languages = null;
			}

			powers = new PowerList(root.getFirstChildElement("powerList"));

			spells = new SpellList(root.getFirstChildElement("spellList"));

			System.out.println("file contentd in memory");

		} catch (Exception e) {
			e.printStackTrace();

		}
	}

	public Character() {
		this.characterName = "test name";
		this.characterClasses = new CharacterClasses();
		race = "human";
		size = "medium";
		gender = "male";
		alignment = "LN";
		religion = "N/A";
		deity = " ";
		height = "5' 8\"";
		weight = "140 lbs";
		looks = " ";

		strength = new AbilityScore();
		dexterity = new AbilityScore();
		constitution = new AbilityScore();
		intelligence = new AbilityScore();
		wisdom = new AbilityScore();
		charisma = new AbilityScore();

		strength.setAbility(Ability.STRENGTH);
		dexterity.setAbility(Ability.DEXTERITY);
		constitution.setAbility(Ability.CONSTITUTION);
		intelligence.setAbility(Ability.INTELLIGENCE);
		wisdom.setAbility(Ability.WISDOM);
		charisma.setAbility(Ability.CHARISMA);

		baseAttackBonus = new BaseAttackBonus();
		attack1 = new Attack();
		attack2 = new Attack();
		attack3 = new Attack();
		attack4 = new Attack();

		speed = 30;
		initiativeModifier = 2;

		grappleModifier = new GrappleModifer();

		fortitude = new SavingThrowData(Ability.CONSTITUTION);
		reflex = new SavingThrowData(Ability.DEXTERITY);
		will = new SavingThrowData(Ability.WISDOM);
		savingThrowConditionalModifiers = new SavingThrowConditional();

		maxHP = 20;
		currentHP = 20;
		nonlethalDamage = 0;

		AC = new ArmorClass();

		experiancePoints = 0;

		lightLoad = 50;
		mediumLoad = 100;
		heavyLoad = 150;

		money = new Money();

		possessionsOnPerson = new Possession[1];
		possessionsNotOnPerson = new Possession[1];

		for (int index = 0; index < 1; index++) {
			possessionsOnPerson[index] = new Possession();
		}
		for (int index = 0; index < 1; index++) {
			possessionsNotOnPerson[index] = new Possession();
		}

		magicItemsWorn = new MagicItems();

		magic = new Magic();

		rebukeUndead = new RebukeUndead();

		spellsTable = new SpellsTable();

		psionics = new Psionics();

		rage = new Rage();

		animalCompanion = new AnimalCompanion();

		skillList = new SkillList();

		racialTaits = new RacialTrait[1];
		for (int index = 0; index < 1; index++) {
			racialTaits[index] = new RacialTrait();
		}

		classFeatures = new ClassFeature[1];
		for (int index = 0; index < 1; index++) {
			classFeatures[index] = new ClassFeature();
		}

		feats = new Feat[1];
		for (int index = 0; index < 1; index++) {
			feats[index] = new Feat();
		}

		languages = new Language[1];
		for (int index = 0; index < 1; index++) {
			languages[index] = new Language();

		}

		powers = new PowerList();

		spells = new SpellList();

		createBaseSkills();

		// testPossessions();

		test();

	}

	public void createBaseSkills() {
		skillList.addSkill(new Skill("Appraise", "", true, false, Ability.INTELLIGENCE, 0));
		skillList.addSkill(new Skill("Balance", "", true, true, Ability.DEXTERITY, 0));
		skillList.addSkill(new Skill("Bluff", "", true, false, Ability.CHARISMA, 0));
		skillList.addSkill(new Skill("climb", "", true, true, Ability.STRENGTH, 0));
		skillList.addSkill(new Skill("Concentration", "", true, false, Ability.CONSTITUTION, 0));
		skillList.addSkill(new Skill("Diplomacy", "", true, false, Ability.CHARISMA, 0));
		skillList.addSkill(new Skill("Disgusie", "", true, false, Ability.CHARISMA, 0));
		skillList.addSkill(new Skill("Escape Artist", "", true, true, Ability.DEXTERITY, 0));
		skillList.addSkill(new Skill("Forgery", "", true, false, Ability.INTELLIGENCE, 0));
		skillList.addSkill(new Skill("Gather Information", "", true, false, Ability.CHARISMA, 0));
		skillList.addSkill(new Skill("Heal", "", true, false, Ability.WISDOM, 0));
		skillList.addSkill(new Skill("Hide", "", true, true, Ability.DEXTERITY, 0));
		skillList.addSkill(new Skill("Intimidate", "", true, false, Ability.CHARISMA, 0));
		skillList.addSkill(new Skill("Jump", "", true, true, Ability.STRENGTH, 0));
		skillList.addSkill(new Skill("Listen", "", true, false, Ability.WISDOM, 0));
		skillList.addSkill(new Skill("Move Silently", "", true, true, Ability.DEXTERITY, 0));
		skillList.addSkill(new Skill("Ride", "", true, false, Ability.DEXTERITY, 0));
		skillList.addSkill(new Skill("Search", "", true, false, Ability.INTELLIGENCE, 0));
		skillList.addSkill(new Skill("Sense Motive", "", true, false, Ability.WISDOM, 0));
		// TODO finish adding the base skills
	}

	// xml methods

	/**
	 * creates a simple bottom level Element. <br />
	 * <<i>name</i>><i>value</i><<i>/name</i>>
	 * 
	 * @param name
	 *            the element name
	 * @param value
	 *            value of the element
	 * @return Element with local name <i>name</i> and value <i>value</i>
	 */
	public static Element makeSimpleElement(String name, String value) {
		Element tmp = new Element(name);
		tmp.appendChild(value);
		return tmp;
	}

	/**
	 * creates a simple bottom level Element. <br />
	 * <<i>name</i>><i>value</i><<i>/name</i>>
	 * 
	 * @param name
	 *            the element name
	 * @param value
	 *            value of the element
	 * @return Element with local name <i>name</i> and value <i>value</i>
	 */
	public static Element makeSimpleElement(String name, int value) {
		return makeSimpleElement(name, "" + value);
	}

	public Element makeSimpleElement(String name, boolean value) {
		if (value) {
			return makeSimpleElement(name, "true");
		} else {
			return makeSimpleElement(name, "false");
		}
	}

	public boolean getElementBoolValue(Element element, String name) {
		return Boolean.parseBoolean(getElementValue(element, name));
	}

	public static String getElementValue(Element element, String elementName) {
		return element.getFirstChildElement(elementName).getValue();
	}

	public static int getElementIntValue(Element element, String elementName) {
		return Integer.parseInt(getElementValue(element, elementName));
	}

	// testing methods

	public void test() {
		testPossessions();
		testSkills();
	}

	public void testPossessions() {
		addPossessionOnPerson(new Possession("test item number 1", "in pocket", "0.5 lbs", 2));
		addPossessionOnPerson(new Possession("test item 2", "in hand", "0.1 lbs", 1));

		addPossessionOnPerson(new Possession("should not be in the output", "not here", "idk", 10000));
		removePossessionOnPerson("shoulc not be in the output");

		addPossessionNotOnPerson(new Possession("house", "home", "a shit load", 1));

		addPossessionNotOnPerson(new Possession("stuff", "not here", "idk", 4));
		removePossessionNotOnPerson("stuff");
	}

	public void testSkills() {
		skillList.setSkillRanks("Bluff", 10);
	}

	public enum AttackType {
		NORMAL,
		FLAT,
		TOUCH
	};
	
	/**
	 * check to see if the attack will hit
	 * @param attackRoll
	 * @param attackType
	 * @return
	 */
	public boolean checkIfAttackHits(int attackRoll, AttackType attackType) {
		boolean attackHits = false;
		switch (attackType) {
		case NORMAL: attackHits = (attackRoll >= AC.getTotal()); break;
		case FLAT: attackHits = (attackRoll >= AC.getFlatFooted()); break;
		case TOUCH: attackHits = (attackRoll >= AC.getTouch()); break;
		}
		return attackHits;
	}
}
